diff --git a/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs b/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs deleted file mode 100644 index e1a645f57..000000000 --- a/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs +++ /dev/null @@ -1,133 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -// ReSharper disable InconsistentNaming - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Defines the format for string-serialized and objects. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class DateTimeFormatAttribute : SerializationAttribute - { - /// - /// Gets the ISO 8601 format string of "yyyy-MM-ddTHH:mm:ss.fffzzz". - /// - public const string FORMAT_ISO_8601 = "yyyy-MM-ddTHH:mm:ss.fffzzz"; - - /// - /// Gets the RFC 1123 format string of "R". - /// - public const string FORMAT_RFC_1123 = "R"; - - /// - /// Gets the general long format. - /// - public const string FORMAT_LONG = "G"; - - /// - /// Gets the general short format. - /// - public const string FORMAT_SHORT = "g"; - - /// - /// Gets the custom datetime format string to use. - /// - public string Format { get; } - - /// - /// Gets the predefined datetime format kind. - /// - public DateTimeFormatKind Kind { get; } - - /// - /// Specifies a predefined format to use. - /// - /// Predefined format kind to use. - public DateTimeFormatAttribute(DateTimeFormatKind kind) - { - if (kind < 0 || kind > DateTimeFormatKind.InvariantLocaleShort) - throw new ArgumentOutOfRangeException(nameof(kind), "Specified format kind is not legal or supported."); - - this.Kind = kind; - this.Format = null; - } - - /// - /// Specifies a custom format to use. - /// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings for more details. - /// - /// Custom format string to use. - public DateTimeFormatAttribute(string format) - { - if (string.IsNullOrWhiteSpace(format)) - throw new ArgumentNullException(nameof(format), "Specified format cannot be null or empty."); - - this.Kind = DateTimeFormatKind.Custom; - this.Format = format; - } - } - - /// - /// Defines which built-in format to use for for and serialization. - /// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings and https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings for more details. - /// - public enum DateTimeFormatKind : int - { - /// - /// Specifies ISO 8601 format, which is equivalent to .NET format string of "yyyy-MM-ddTHH:mm:ss.fffzzz". - /// - ISO8601 = 0, - - /// - /// Specifies RFC 1123 format, which is equivalent to .NET format string of "R". - /// - RFC1123 = 1, - - /// - /// Specifies a format defined by , with a format string of "G". This format is not recommended for portability reasons. - /// - CurrentLocaleLong = 2, - - /// - /// Specifies a format defined by , with a format string of "g". This format is not recommended for portability reasons. - /// - CurrentLocaleShort = 3, - - /// - /// Specifies a format defined by , with a format string of "G". - /// - InvariantLocaleLong = 4, - - /// - /// Specifies a format defined by , with a format string of "g". - /// - InvariantLocaleShort = 5, - - /// - /// Specifies a custom format. This value is not usable directly. - /// - Custom = int.MaxValue - } -} diff --git a/DisCatSharp.Common/Attributes/DecomposerAttribute.cs b/DisCatSharp.Common/Attributes/DecomposerAttribute.cs deleted file mode 100644 index b6ba47f89..000000000 --- a/DisCatSharp.Common/Attributes/DecomposerAttribute.cs +++ /dev/null @@ -1,50 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Specifies a decomposer for a given type or property. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field)] - public sealed class DecomposerAttribute : SerializationAttribute - { - /// - /// Gets the type of the decomposer. - /// - public Type DecomposerType { get; } - - /// - /// Specifies a decomposer for given type or property. - /// - /// Type of decomposer to use. - public DecomposerAttribute(Type type) - { - if (!typeof(IDecomposer).IsAssignableFrom(type) || !type.IsClass || type.IsAbstract) // abstract covers static - static = abstract + sealed - throw new ArgumentException("Invalid type specified. Must be a non-abstract class which implements DisCatSharp.Common.Serialization.IDecomposer interface.", nameof(type)); - - this.DecomposerType = type; - } - } -} diff --git a/DisCatSharp.Common/Attributes/EnumAttributes.cs b/DisCatSharp.Common/Attributes/EnumAttributes.cs deleted file mode 100644 index 7c2485cc2..000000000 --- a/DisCatSharp.Common/Attributes/EnumAttributes.cs +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Specifies that this enum should be serialized and deserialized as its underlying numeric type. - /// This is used to change the behaviour of enum serialization. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class NumericEnumAttribute : SerializationAttribute - { } - - /// - /// Specifies that this enum should be serialized and deserialized as its string representation. - /// This is used to change the behaviour of enum serialization. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class StringEnumAttribute : SerializationAttribute - { } -} diff --git a/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs b/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs deleted file mode 100644 index afb4cc8ac..000000000 --- a/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs +++ /dev/null @@ -1,35 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Specifies that if the value of the field or property is null, it should be included in the serialized data. - /// This alters the default behaviour of ignoring nulls. - /// - [Obsolete("Use [DataMember] with EmitDefaultValue = true.")] - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class IncludeNullAttribute : SerializationAttribute - { } -} diff --git a/DisCatSharp.Common/Attributes/Int53Attribute.cs b/DisCatSharp.Common/Attributes/Int53Attribute.cs deleted file mode 100644 index b8bad4b91..000000000 --- a/DisCatSharp.Common/Attributes/Int53Attribute.cs +++ /dev/null @@ -1,46 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Specifies that this 64-bit integer uses no more than 53 bits to represent its value. - /// This is used to indicate that large numbers are safe for direct serialization into formats which do support 64-bit integers natively (such as JSON). - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class Int53Attribute : SerializationAttribute - { - /// - /// Gets the maximum safe value representable as an integer by a IEEE754 64-bit binary floating point value. - /// This value equals to 9007199254740991. - /// - public const long MAX_VALUE = (1L << 53) - 1; - - /// - /// Gets the minimum safe value representable as an integer by a IEEE754 64-bit binary floating point value. - /// This value equals to -9007199254740991. - /// - public const long MIN_VALUE = -MAX_VALUE; - } -} diff --git a/DisCatSharp.Common/Attributes/SerializationAttribute.cs b/DisCatSharp.Common/Attributes/SerializationAttribute.cs deleted file mode 100644 index 950605130..000000000 --- a/DisCatSharp.Common/Attributes/SerializationAttribute.cs +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// ABC for serialization attributes. - /// - public abstract class SerializationAttribute : Attribute - { } -} diff --git a/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs b/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs deleted file mode 100644 index 914d706c3..000000000 --- a/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Declares name of a property in serialized data. This is used for mapping serialized data to object properties and fields. - /// - [Obsolete("Use [DataMember] with set Name instead.")] - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class SerializedNameAttribute : SerializationAttribute - { - /// - /// Gets the serialized name of the field or property. - /// - public string Name { get; } - - /// - /// Declares name of a property in serialized data. This is used for mapping serialized data to object properties and fields. - /// - /// Name of the field or property in serialized data. - public SerializedNameAttribute(string name) - { - this.Name = name; - } - } -} diff --git a/DisCatSharp.Common/Attributes/TimeSpanAttributes.cs b/DisCatSharp.Common/Attributes/TimeSpanAttributes.cs deleted file mode 100644 index b88643fb5..000000000 --- a/DisCatSharp.Common/Attributes/TimeSpanAttributes.cs +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Specifies that this will be serialized as a number of whole seconds. - /// This value will always be serialized as a number. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class TimeSpanSecondsAttribute : SerializationAttribute - { } - - /// - /// Specifies that this will be serialized as a number of whole milliseconds. - /// This value will always be serialized as a number. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class TimeSpanMillisecondsAttribute : SerializationAttribute - { } -} diff --git a/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs b/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs deleted file mode 100644 index 8cfd15cf4..000000000 --- a/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs +++ /dev/null @@ -1,133 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -// ReSharper disable InconsistentNaming - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Defines the format for string-serialized objects. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class TimeSpanFormatAttribute : SerializationAttribute - { - /// - /// Gets the ISO 8601 format string of @"ddThh\:mm\:ss\.fff". - /// - public const string FORMAT_ISO_8601 = @"ddThh\:mm\:ss\.fff"; - - /// - /// Gets the constant format. - /// - public const string FORMAT_CONSTANT = "c"; - - /// - /// Gets the general long format. - /// - public const string FORMAT_LONG = "G"; - - /// - /// Gets the general short format. - /// - public const string FORMAT_SHORT = "g"; - - /// - /// Gets the custom datetime format string to use. - /// - public string Format { get; } - - /// - /// Gets the predefined datetime format kind. - /// - public TimeSpanFormatKind Kind { get; } - - /// - /// Specifies a predefined format to use. - /// - /// Predefined format kind to use. - public TimeSpanFormatAttribute(TimeSpanFormatKind kind) - { - if (kind < 0 || kind > TimeSpanFormatKind.InvariantLocaleShort) - throw new ArgumentOutOfRangeException(nameof(kind), "Specified format kind is not legal or supported."); - - this.Kind = kind; - this.Format = null; - } - - /// - /// Specifies a custom format to use. - /// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-timespan-format-strings for more details. - /// - /// Custom format string to use. - public TimeSpanFormatAttribute(string format) - { - if (string.IsNullOrWhiteSpace(format)) - throw new ArgumentNullException(nameof(format), "Specified format cannot be null or empty."); - - this.Kind = TimeSpanFormatKind.Custom; - this.Format = format; - } - } - - /// - /// Defines which built-in format to use for serialization. - /// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings and https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-timespan-format-strings for more details. - /// - public enum TimeSpanFormatKind : int - { - /// - /// Specifies ISO 8601-like time format, which is equivalent to .NET format string of @"ddThh\:mm\:ss\.fff". - /// - ISO8601 = 0, - - /// - /// Specifies a format defined by , with a format string of "c". - /// - InvariantConstant = 1, - - /// - /// Specifies a format defined by , with a format string of "G". This format is not recommended for portability reasons. - /// - CurrentLocaleLong = 2, - - /// - /// Specifies a format defined by , with a format string of "g". This format is not recommended for portability reasons. - /// - CurrentLocaleShort = 3, - - /// - /// Specifies a format defined by , with a format string of "G". This format is not recommended for portability reasons. - /// - InvariantLocaleLong = 4, - - /// - /// Specifies a format defined by , with a format string of "g". This format is not recommended for portability reasons. - /// - InvariantLocaleShort = 5, - - /// - /// Specifies a custom format. This value is not usable directly. - /// - Custom = int.MaxValue - } -} diff --git a/DisCatSharp.Common/Attributes/UnixTimestampAttributes.cs b/DisCatSharp.Common/Attributes/UnixTimestampAttributes.cs deleted file mode 100644 index 2bf2ba457..000000000 --- a/DisCatSharp.Common/Attributes/UnixTimestampAttributes.cs +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Specifies that this or will be serialized as Unix timestamp seconds. - /// This value will always be serialized as a number. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class UnixSecondsAttribute : SerializationAttribute - { } - - /// - /// Specifies that this or will be serialized as Unix timestamp milliseconds. - /// This value will always be serialized as a number. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public sealed class UnixMillisecondsAttribute : SerializationAttribute - { } -} diff --git a/DisCatSharp.Common/GlobalSuppressions.cs b/DisCatSharp.Common/GlobalSuppressions.cs deleted file mode 100644 index cb38bcb49..000000000 --- a/DisCatSharp.Common/GlobalSuppressions.cs +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Style", "IDE0090:Use 'new(...)'", Justification = "", Scope = "member", Target = "~F:DisCatSharp.Common.Utilities.AsyncEvent`2._lock")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.Enumerator.Dispose")] -[assembly: SuppressMessage("Style", "IDE0083:Use pattern matching", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.System#Collections#IDictionary#Add(System.Object,System.Object)")] -[assembly: SuppressMessage("Style", "IDE0083:Use pattern matching", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.System#Collections#IDictionary#Contains(System.Object)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.System#Collections#IDictionary#Contains(System.Object)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0083:Use pattern matching", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.System#Collections#IDictionary#Remove(System.Object)")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.TryGetValue(System.String,`0@)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupDictionary`1.TryRemove(System.String,`0@)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Extensions.FirstTwoOrDefault``1(System.Collections.Generic.IEnumerable{``0})~System.ValueTuple{``0,``0}")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Extensions.IsInRange(System.Double,System.Double,System.Double,System.Boolean)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Extensions.IsInRange(System.Single,System.Single,System.Single,System.Boolean)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0047:Remove unnecessary parentheses", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Types.ContinuousMemoryBuffer`1.Read(System.Span{`0},System.UInt64,System.Int32@)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Types.ContinuousMemoryBuffer`1.ToArray~`0[]")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Utilities.AsyncEvent`2.UnregisterAll")] -[assembly: SuppressMessage("Style", "IDE0090:Use 'new(...)'", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupDictionary`1.Enumerator.System#Collections#IDictionaryEnumerator#Entry")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupDictionary`1.Item(System.ReadOnlySpan{System.Char})")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupDictionary`1.Item(System.String)")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupDictionary`1.System#Collections#IDictionary#Item(System.Object)")] -[assembly: SuppressMessage("Style", "IDE0083:Use pattern matching", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupDictionary`1.System#Collections#IDictionary#Item(System.Object)")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupReadOnlyDictionary`1.Enumerator.Dispose")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.CharSpanLookupReadOnlyDictionary`1.TryGetValue(System.String,`0@)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetBytes(System.Span{System.Byte})")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetNonZeroBytes(System.Span{System.Byte})")] -[assembly: SuppressMessage("Style", "IDE0047:Remove unnecessary parentheses", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Types.MemoryBuffer`1.Grow(System.Int32)")] -[assembly: SuppressMessage("Style", "IDE0047:Remove unnecessary parentheses", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Types.MemoryBuffer`1.Read(System.Span{`0},System.UInt64,System.Int32@)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupReadOnlyDictionary`1.Item(System.ReadOnlySpan{System.Char})")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Common.CharSpanLookupReadOnlyDictionary`1.Item(System.String)")] -[assembly: SuppressMessage("Style", "IDE0090:Use 'new(...)'", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Optional.FromDefaultValue``1~DisCatSharp.Common.Optional{``0}")] -[assembly: SuppressMessage("Style", "IDE0090:Use 'new(...)'", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Optional.FromValue``1(``0)~DisCatSharp.Common.Optional{``0}")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Optional`1.Equals(`0)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Optional`1.Equals(DisCatSharp.Common.Optional`1)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Optional`1.Equals(System.Object)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0090:Use 'new(...)'", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Optional`1.op_Implicit(`0)~DisCatSharp.Common.Optional`1")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetBytes(System.Byte[])")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetInt16(System.Int16,System.Int16)~System.Int16")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetInt32(System.Int32,System.Int32)~System.Int32")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetInt64(System.Int64,System.Int64)~System.Int64")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetInt8(System.SByte,System.SByte)~System.SByte")] -[assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetNonZeroBytes(System.Byte[])")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt16(System.UInt16,System.UInt16)~System.UInt16")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt16(System.UInt16,System.UInt16)~System.UInt16")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt32(System.UInt32,System.UInt32)~System.UInt32")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt32(System.UInt32,System.UInt32)~System.UInt32")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt64(System.UInt64,System.UInt64)~System.UInt64")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt64(System.UInt64,System.UInt64)~System.UInt64")] -[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt8(System.Byte,System.Byte)~System.Byte")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.SecureRandom.GetUInt8(System.Byte,System.Byte)~System.Byte")] -[assembly: SuppressMessage("Style", "IDE0045:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Utilities.AsyncExecutor.Execute(System.Threading.Tasks.Task)")] -[assembly: SuppressMessage("Style", "IDE0062:Make local function 'static'", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Utilities.AsyncExecutor.Execute(System.Threading.Tasks.Task)")] -[assembly: SuppressMessage("Style", "IDE0045:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Utilities.AsyncExecutor.Execute``1(System.Threading.Tasks.Task{``0})~``0")] -[assembly: SuppressMessage("Style", "IDE0062:Make local function 'static'", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Utilities.AsyncExecutor.Execute``1(System.Threading.Tasks.Task{``0})~``0")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Common.Utilities.ReflectionUtilities.ToDictionary``1(``0)~System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object}")] diff --git a/DisCatSharp.Common/RegularExpressions/CommonRegEx.cs b/DisCatSharp.Common/RegularExpressions/CommonRegEx.cs index d436083d6..34f33a757 100644 --- a/DisCatSharp.Common/RegularExpressions/CommonRegEx.cs +++ b/DisCatSharp.Common/RegularExpressions/CommonRegEx.cs @@ -1,75 +1,50 @@ // This file is part of the DisCatSharp project, based off DSharpPlus. // // Copyright (c) 2021-2022 AITSYS // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using System.Text.RegularExpressions; namespace DisCatSharp.Common.RegularExpressions { /// /// Provides common regex. /// public static class CommonRegEx { /// /// Represents a hex color string. /// public static Regex HexColorString => new(@"^#?([a-fA-F0-9]{6})$", RegexOptions.ECMAScript | RegexOptions.Compiled); /// /// Represents a rgb color string. /// public static Regex RgbColorString => new(@"^(\d{1,3})\s*?,\s*?(\d{1,3}),\s*?(\d{1,3})$", RegexOptions.ECMAScript | RegexOptions.Compiled); /// /// Represents a timespan. /// public static Regex TimeSpan => new(@"^(?\d+d\s*)?(?\d{1,2}h\s*)?(?\d{1,2}m\s*)?(?\d{1,2}s\s*)?$", RegexOptions.ECMAScript | RegexOptions.Compiled); - - /// - /// Represents a advanced youtube regex. - /// Named groups: - /// - /// - /// group - /// description - /// - /// - /// id - /// Video ID - /// - /// - /// list - /// List ID - /// - /// - /// index - /// List index - /// - /// - /// - public static Regex AdvancedYoutubeRegex - => new(@"http(s)?:\/\/(www\.)?youtu(\.be|be\.com)\/(watch\?v=|playlist)?(?\w{1,})?((\?|\&)list=(?\w{1,}))(&index=(?\d{1,}))?", RegexOptions.ECMAScript | RegexOptions.Compiled); } } diff --git a/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs b/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs deleted file mode 100644 index 11806b9d0..000000000 --- a/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs +++ /dev/null @@ -1,814 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Immutable; - -namespace DisCatSharp.Common -{ - /// - /// Represents collection of string keys and values, allowing the use of for dictionary operations. - /// - /// Type of items in this dictionary. - public sealed class CharSpanLookupDictionary : - IDictionary, - IReadOnlyDictionary, - IDictionary - { - /// - /// Gets the collection of all keys present in this dictionary. - /// - public IEnumerable Keys => this.GetKeysInternal(); - /// - /// Gets the keys. - /// - ICollection IDictionary.Keys => this.GetKeysInternal(); - /// - /// Gets the keys. - /// - ICollection IDictionary.Keys => this.GetKeysInternal(); - - /// - /// Gets the collection of all values present in this dictionary. - /// - public IEnumerable Values => this.GetValuesInternal(); - /// - /// Gets the values. - /// - ICollection IDictionary.Values => this.GetValuesInternal(); - /// - /// Gets the values. - /// - ICollection IDictionary.Values => this.GetValuesInternal(); - - /// - /// Gets the total number of items in this dictionary. - /// - public int Count { get; private set; } - - /// - /// Gets whether this dictionary is read-only. - /// - public bool IsReadOnly => false; - - /// - /// Gets whether this dictionary has a fixed size. - /// - public bool IsFixedSize => false; - - /// - /// Gets whether this dictionary is considered thread-safe. - /// - public bool IsSynchronized => false; - - /// - /// Gets the object which allows synchronizing access to this dictionary. - /// - public object SyncRoot { get; } = new(); - - /// - /// Gets or sets a value corresponding to given key in this dictionary. - /// - /// Key to get or set the value for. - /// Value matching the supplied key, if applicable. - public TValue this[string key] - { - get - { - if (key == null) - throw new ArgumentNullException(nameof(key)); - - if (!this.TryRetrieveInternal(key.AsSpan(), out var value)) - throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); - - return value; - } - - set - { - if (key == null) - throw new ArgumentNullException(nameof(key)); - - this.TryInsertInternal(key, value, true); - } - } - - /// - /// Gets or sets a value corresponding to given key in this dictionary. - /// - /// Key to get or set the value for. - /// Value matching the supplied key, if applicable. - public TValue this[ReadOnlySpan key] - { - get - { - if (!this.TryRetrieveInternal(key, out var value)) - throw new KeyNotFoundException($"The given key was not present in the dictionary."); - - return value; - } - - set - { - unsafe - { - fixed (char* chars = &key.GetPinnableReference()) - this.TryInsertInternal(new string(chars, 0, key.Length), value, true); - } - } - } - - object IDictionary.this[object key] - { - get - { - if (!(key is string tkey)) - throw new ArgumentException("Key needs to be an instance of a string."); - - if (!this.TryRetrieveInternal(tkey.AsSpan(), out var value)) - throw new KeyNotFoundException($"The given key '{tkey}' was not present in the dictionary."); - - return value; - } - - set - { - if (!(key is string tkey)) - throw new ArgumentException("Key needs to be an instance of a string."); - - if (!(value is TValue tvalue)) - { - tvalue = default; - if (tvalue != null) - throw new ArgumentException($"Value needs to be an instance of {typeof(TValue)}."); - } - - this.TryInsertInternal(tkey, tvalue, true); - } - } - - /// - /// Gets the internal buckets. - /// - private readonly Dictionary _internalBuckets; - - /// - /// Creates a new, empty with string keys and items of type . - /// - public CharSpanLookupDictionary() - { - this._internalBuckets = new Dictionary(); - } - - /// - /// Creates a new, empty with string keys and items of type and sets its initial capacity to specified value. - /// - /// Initial capacity of the dictionary. - public CharSpanLookupDictionary(int initialCapacity) - { - this._internalBuckets = new Dictionary(initialCapacity); - } - - /// - /// Creates a new with string keys and items of type and populates it with key-value pairs from supplied dictionary. - /// - /// Dictionary containing items to populate this dictionary with. - public CharSpanLookupDictionary(IDictionary values) - : this(values.Count) - { - foreach (var (k, v) in values) - this.Add(k, v); - } - - /// - /// Creates a new with string keys and items of type and populates it with key-value pairs from supplied dictionary. - /// - /// Dictionary containing items to populate this dictionary with. - public CharSpanLookupDictionary(IReadOnlyDictionary values) - : this(values.Count) - { - foreach (var (k, v) in values) - this.Add(k, v); - } - - /// - /// Creates a new with string keys and items of type and populates it with key-value pairs from supplied key-value collection. - /// - /// Dictionary containing items to populate this dictionary with. - public CharSpanLookupDictionary(IEnumerable> values) - : this() - { - foreach (var (k, v) in values) - this.Add(k, v); - } - - /// - /// Inserts a specific key and corresponding value into this dictionary. - /// - /// Key to insert. - /// Value corresponding to this key. - public void Add(string key, TValue value) - { - if (!this.TryInsertInternal(key, value, false)) - throw new ArgumentException("Given key is already present in the dictionary.", nameof(key)); - } - - /// - /// Inserts a specific key and corresponding value into this dictionary. - /// - /// Key to insert. - /// Value corresponding to this key. - public void Add(ReadOnlySpan key, TValue value) - { - unsafe - { - fixed (char* chars = &key.GetPinnableReference()) - if (!this.TryInsertInternal(new string(chars, 0, key.Length), value, false)) - throw new ArgumentException("Given key is already present in the dictionary.", nameof(key)); - } - } - - /// - /// Attempts to insert a specific key and corresponding value into this dictionary. - /// - /// Key to insert. - /// Value corresponding to this key. - /// Whether the operation was successful. - public bool TryAdd(string key, TValue value) - => this.TryInsertInternal(key, value, false); - - /// - /// Attempts to insert a specific key and corresponding value into this dictionary. - /// - /// Key to insert. - /// Value corresponding to this key. - /// Whether the operation was successful. - public bool TryAdd(ReadOnlySpan key, TValue value) - { - unsafe - { - fixed (char* chars = &key.GetPinnableReference()) - return this.TryInsertInternal(new string(chars, 0, key.Length), value, false); - } - } - - /// - /// Attempts to retrieve a value corresponding to the supplied key from this dictionary. - /// - /// Key to retrieve the value for. - /// Retrieved value. - /// Whether the operation was successful. - public bool TryGetValue(string key, out TValue value) - { - if (key == null) - throw new ArgumentNullException(nameof(key)); - - return this.TryRetrieveInternal(key.AsSpan(), out value); - } - - /// - /// Attempts to retrieve a value corresponding to the supplied key from this dictionary. - /// - /// Key to retrieve the value for. - /// Retrieved value. - /// Whether the operation was successful. - public bool TryGetValue(ReadOnlySpan key, out TValue value) - => this.TryRetrieveInternal(key, out value); - - /// - /// Attempts to remove a value corresponding to the supplied key from this dictionary. - /// - /// Key to remove the value for. - /// Removed value. - /// Whether the operation was successful. - public bool TryRemove(string key, out TValue value) - { - if (key == null) - throw new ArgumentNullException(nameof(key)); - - return this.TryRemoveInternal(key.AsSpan(), out value); - } - - /// - /// Attempts to remove a value corresponding to the supplied key from this dictionary. - /// - /// Key to remove the value for. - /// Removed value. - /// Whether the operation was successful. - public bool TryRemove(ReadOnlySpan key, out TValue value) - => this.TryRemoveInternal(key, out value); - - /// - /// Checks whether this dictionary contains the specified key. - /// - /// Key to check for in this dictionary. - /// Whether the key was present in the dictionary. - public bool ContainsKey(string key) - => this.ContainsKeyInternal(key.AsSpan()); - - /// - /// Checks whether this dictionary contains the specified key. - /// - /// Key to check for in this dictionary. - /// Whether the key was present in the dictionary. - public bool ContainsKey(ReadOnlySpan key) - => this.ContainsKeyInternal(key); - - /// - /// Removes all items from this dictionary. - /// - public void Clear() - { - this._internalBuckets.Clear(); - this.Count = 0; - } - - /// - /// Gets an enumerator over key-value pairs in this dictionary. - /// - /// - public IEnumerator> GetEnumerator() - => new Enumerator(this); - - /// - /// Removes the. - /// - /// The key. - /// A bool. - bool IDictionary.Remove(string key) - => this.TryRemove(key.AsSpan(), out _); - - /// - /// Adds the. - /// - /// The key. - /// The value. - void IDictionary.Add(object key, object value) - { - if (!(key is string tkey)) - throw new ArgumentException("Key needs to be an instance of a string."); - - if (!(value is TValue tvalue)) - { - tvalue = default; - if (tvalue != null) - throw new ArgumentException($"Value needs to be an instance of {typeof(TValue)}."); - } - - this.Add(tkey, tvalue); - } - - /// - /// Removes the. - /// - /// The key. - void IDictionary.Remove(object key) - { - if (!(key is string tkey)) - throw new ArgumentException("Key needs to be an instance of a string."); - - this.TryRemove(tkey, out _); - } - - /// - /// Contains the. - /// - /// The key. - /// A bool. - bool IDictionary.Contains(object key) - { - if (!(key is string tkey)) - throw new ArgumentException("Key needs to be an instance of a string."); - - return this.ContainsKey(tkey); - } - - /// - /// Gets the enumerator. - /// - /// An IDictionaryEnumerator. - IDictionaryEnumerator IDictionary.GetEnumerator() - => new Enumerator(this); - - /// - /// Adds the. - /// - /// The item. - void ICollection>.Add(KeyValuePair item) - => this.Add(item.Key, item.Value); - - /// - /// Removes the. - /// - /// The item. - /// A bool. - bool ICollection>.Remove(KeyValuePair item) - => this.TryRemove(item.Key, out _); - - /// - /// Contains the. - /// - /// The item. - /// A bool. - bool ICollection>.Contains(KeyValuePair item) - => this.TryGetValue(item.Key, out var value) && EqualityComparer.Default.Equals(value, item.Value); - - /// - /// Copies the to. - /// - /// The array. - /// The array index. - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - if (array.Length - arrayIndex < this.Count) - throw new ArgumentException("Target array is too small.", nameof(array)); - - var i = arrayIndex; - foreach (var (k, v) in this._internalBuckets) - { - var kdv = v; - while (kdv != null) - { - array[i++] = new KeyValuePair(kdv.Key, kdv.Value); - kdv = kdv.Next; - } - } - } - - /// - /// Copies the to. - /// - /// The array. - /// The array index. - void ICollection.CopyTo(Array array, int arrayIndex) - { - if (array is KeyValuePair[] tarray) - { - (this as ICollection>).CopyTo(tarray, arrayIndex); - return; - } - - if (array is not object[]) - throw new ArgumentException($"Array needs to be an instance of {typeof(TValue[])} or object[]."); - - var i = arrayIndex; - foreach (var (k, v) in this._internalBuckets) - { - var kdv = v; - while (kdv != null) - { - array.SetValue(new KeyValuePair(kdv.Key, kdv.Value), i++); - kdv = kdv.Next; - } - } - } - - /// - /// Gets the enumerator. - /// - /// An IEnumerator. - IEnumerator IEnumerable.GetEnumerator() - => this.GetEnumerator(); - - /// - /// Tries the insert internal. - /// - /// The key. - /// The value. - /// If true, replace. - /// A bool. - private bool TryInsertInternal(string key, TValue value, bool replace) - { - if (key == null) - throw new ArgumentNullException(nameof(key), "Key cannot be null."); - - var hash = key.CalculateKnuthHash(); - if (!this._internalBuckets.ContainsKey(hash)) - { - this._internalBuckets.Add(hash, new KeyedValue(key, hash, value)); - this.Count++; - return true; - } - - var kdv = this._internalBuckets[hash]; - var kdvLast = kdv; - while (kdv != null) - { - if (kdv.Key == key) - { - if (!replace) - return false; - - kdv.Value = value; - return true; - } - - kdvLast = kdv; - kdv = kdv.Next; - } - - kdvLast.Next = new KeyedValue(key, hash, value); - this.Count++; - return true; - } - - /// - /// Tries the retrieve internal. - /// - /// The key. - /// The value. - /// A bool. - private bool TryRetrieveInternal(ReadOnlySpan key, out TValue value) - { - value = default; - - var hash = key.CalculateKnuthHash(); - if (!this._internalBuckets.TryGetValue(hash, out var kdv)) - return false; - - while (kdv != null) - { - if (key.SequenceEqual(kdv.Key.AsSpan())) - { - value = kdv.Value; - return true; - } - } - - return false; - } - - /// - /// Tries the remove internal. - /// - /// The key. - /// The value. - /// A bool. - private bool TryRemoveInternal(ReadOnlySpan key, out TValue value) - { - value = default; - - var hash = key.CalculateKnuthHash(); - if (!this._internalBuckets.TryGetValue(hash, out var kdv)) - return false; - - if (kdv.Next == null && key.SequenceEqual(kdv.Key.AsSpan())) - { - // Only bucket under this hash and key matches, pop the entire bucket - - value = kdv.Value; - this._internalBuckets.Remove(hash); - this.Count--; - return true; - } - else if (kdv.Next == null) - { - // Only bucket under this hash and key does not match, cannot remove - - return false; - } - else if (key.SequenceEqual(kdv.Key.AsSpan())) - { - // First key in the bucket matches, pop it and set its child as current bucket - - value = kdv.Value; - this._internalBuckets[hash] = kdv.Next; - this.Count--; - return true; - } - - var kdvLast = kdv; - kdv = kdv.Next; - while (kdv != null) - { - if (key.SequenceEqual(kdv.Key.AsSpan())) - { - // Key matched, remove this bucket from the chain - - value = kdv.Value; - kdvLast.Next = kdv.Next; - this.Count--; - return true; - } - - kdvLast = kdv; - kdv = kdv.Next; - } - - return false; - } - - /// - /// Contains the key internal. - /// - /// The key. - /// A bool. - private bool ContainsKeyInternal(ReadOnlySpan key) - { - var hash = key.CalculateKnuthHash(); - if (!this._internalBuckets.TryGetValue(hash, out var kdv)) - return false; - - while (kdv != null) - { - if (key.SequenceEqual(kdv.Key.AsSpan())) - return true; - - kdv = kdv.Next; - } - - return false; - } - - /// - /// Gets the keys internal. - /// - /// An ImmutableArray. - private ImmutableArray GetKeysInternal() - { - var builder = ImmutableArray.CreateBuilder(this.Count); - foreach (var value in this._internalBuckets.Values) - { - var kdv = value; - while (kdv != null) - { - builder.Add(kdv.Key); - kdv = kdv.Next; - } - } - - return builder.MoveToImmutable(); - } - - /// - /// Gets the values internal. - /// - /// An ImmutableArray. - private ImmutableArray GetValuesInternal() - { - var builder = ImmutableArray.CreateBuilder(this.Count); - foreach (var value in this._internalBuckets.Values) - { - var kdv = value; - while (kdv != null) - { - builder.Add(kdv.Value); - kdv = kdv.Next; - } - } - - return builder.MoveToImmutable(); - } - - /// - /// The keyed value. - /// - private class KeyedValue - { - /// - /// Gets the key hash. - /// - public ulong KeyHash { get; } - /// - /// Gets the key. - /// - public string Key { get; } - /// - /// Gets or sets the value. - /// - public TValue Value { get; set; } - - /// - /// Gets or sets the next. - /// - public KeyedValue Next { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The key. - /// The key hash. - /// The value. - public KeyedValue(string key, ulong keyHash, TValue value) - { - this.KeyHash = keyHash; - this.Key = key; - this.Value = value; - } - } - - /// - /// The enumerator. - /// - private class Enumerator : - IEnumerator>, - IDictionaryEnumerator - { - /// - /// Gets the current. - /// - public KeyValuePair Current { get; private set; } - /// - /// Gets the current. - /// - object IEnumerator.Current => this.Current; - /// - /// Gets the key. - /// - object IDictionaryEnumerator.Key => this.Current.Key; - /// - /// Gets the value. - /// - object IDictionaryEnumerator.Value => this.Current.Value; - /// - /// Gets the entry. - /// - DictionaryEntry IDictionaryEnumerator.Entry => new(this.Current.Key, this.Current.Value); - - /// - /// Gets the internal dictionary. - /// - private readonly CharSpanLookupDictionary _internalDictionary; - - /// - /// Gets the internal enumerator. - /// - private readonly IEnumerator> _internalEnumerator; - - /// - /// Gets or sets the current value. - /// - private KeyedValue _currentValue; - - /// - /// Initializes a new instance of the class. - /// - /// The sp dict. - public Enumerator(CharSpanLookupDictionary spDict) - { - this._internalDictionary = spDict; - this._internalEnumerator = this._internalDictionary._internalBuckets.GetEnumerator(); - } - - /// - /// Moves the next. - /// - /// A bool. - public bool MoveNext() - { - var kdv = this._currentValue; - if (kdv == null) - { - if (!this._internalEnumerator.MoveNext()) - return false; - - kdv = this._internalEnumerator.Current.Value; - this.Current = new KeyValuePair(kdv.Key, kdv.Value); - - this._currentValue = kdv.Next; - return true; - } - - this.Current = new KeyValuePair(kdv.Key, kdv.Value); - this._currentValue = kdv.Next; - return true; - } - - /// - /// Resets the. - /// - public void Reset() - { - this._internalEnumerator.Reset(); - this.Current = default; - this._currentValue = null; - } - - /// - /// Disposes the. - /// - public void Dispose() => this.Reset(); - } - } -} diff --git a/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs b/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs deleted file mode 100644 index 7a5a73a9f..000000000 --- a/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs +++ /dev/null @@ -1,416 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Collections.ObjectModel; - -namespace DisCatSharp.Common -{ - /// - /// Represents collection of string keys and values, allowing the use of for dictionary operations. - /// - /// Type of items in this dictionary. - public sealed class CharSpanLookupReadOnlyDictionary : IReadOnlyDictionary - { - /// - /// Gets the collection of all keys present in this dictionary. - /// - public IEnumerable Keys => this.GetKeysInternal(); - - /// - /// Gets the collection of all values present in this dictionary. - /// - public IEnumerable Values => this.GetValuesInternal(); - - /// - /// Gets the total number of items in this dictionary. - /// - public int Count { get; } - - /// - /// Gets a value corresponding to given key in this dictionary. - /// - /// Key to get or set the value for. - /// Value matching the supplied key, if applicable. - public TValue this[string key] - { - get - { - if (key == null) - throw new ArgumentNullException(nameof(key)); - - if (!this.TryRetrieveInternal(key.AsSpan(), out var value)) - throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); - - return value; - } - } - - /// - /// Gets a value corresponding to given key in this dictionary. - /// - /// Key to get or set the value for. - /// Value matching the supplied key, if applicable. - public TValue this[ReadOnlySpan key] - { - get - { - if (!this.TryRetrieveInternal(key, out var value)) - throw new KeyNotFoundException($"The given key was not present in the dictionary."); - - return value; - } - } - - /// - /// Gets the internal buckets. - /// - private readonly IReadOnlyDictionary _internalBuckets; - - /// - /// Creates a new with string keys and items of type and populates it with key-value pairs from supplied dictionary. - /// - /// Dictionary containing items to populate this dictionary with. - public CharSpanLookupReadOnlyDictionary(IDictionary values) - : this(values as IEnumerable>) - { } - - /// - /// Creates a new with string keys and items of type and populates it with key-value pairs from supplied dictionary. - /// - /// Dictionary containing items to populate this dictionary with. - public CharSpanLookupReadOnlyDictionary(IReadOnlyDictionary values) - : this(values as IEnumerable>) - { } - - /// - /// Creates a new with string keys and items of type and populates it with key-value pairs from supplied key-value collection. - /// - /// Dictionary containing items to populate this dictionary with. - public CharSpanLookupReadOnlyDictionary(IEnumerable> values) - { - this._internalBuckets = PrepareItems(values, out var count); - this.Count = count; - } - - /// - /// Attempts to retrieve a value corresponding to the supplied key from this dictionary. - /// - /// Key to retrieve the value for. - /// Retrieved value. - /// Whether the operation was successful. - public bool TryGetValue(string key, out TValue value) - { - if (key == null) - throw new ArgumentNullException(nameof(key)); - - return this.TryRetrieveInternal(key.AsSpan(), out value); - } - - /// - /// Attempts to retrieve a value corresponding to the supplied key from this dictionary. - /// - /// Key to retrieve the value for. - /// Retrieved value. - /// Whether the operation was successful. - public bool TryGetValue(ReadOnlySpan key, out TValue value) - => this.TryRetrieveInternal(key, out value); - - /// - /// Checks whether this dictionary contains the specified key. - /// - /// Key to check for in this dictionary. - /// Whether the key was present in the dictionary. - public bool ContainsKey(string key) - => this.ContainsKeyInternal(key.AsSpan()); - - /// - /// Checks whether this dictionary contains the specified key. - /// - /// Key to check for in this dictionary. - /// Whether the key was present in the dictionary. - public bool ContainsKey(ReadOnlySpan key) - => this.ContainsKeyInternal(key); - - /// - /// Gets an enumerator over key-value pairs in this dictionary. - /// - /// - public IEnumerator> GetEnumerator() - => new Enumerator(this); - - /// - /// Gets the enumerator. - /// - /// An IEnumerator. - IEnumerator IEnumerable.GetEnumerator() - => this.GetEnumerator(); - - /// - /// Tries the retrieve internal. - /// - /// The key. - /// The value. - /// A bool. - private bool TryRetrieveInternal(ReadOnlySpan key, out TValue value) - { - value = default; - - var hash = key.CalculateKnuthHash(); - if (!this._internalBuckets.TryGetValue(hash, out var kdv)) - return false; - - while (kdv != null) - { - if (key.SequenceEqual(kdv.Key.AsSpan())) - { - value = kdv.Value; - return true; - } - } - - return false; - } - - /// - /// Contains the key internal. - /// - /// The key. - /// A bool. - private bool ContainsKeyInternal(ReadOnlySpan key) - { - var hash = key.CalculateKnuthHash(); - if (!this._internalBuckets.TryGetValue(hash, out var kdv)) - return false; - - while (kdv != null) - { - if (key.SequenceEqual(kdv.Key.AsSpan())) - return true; - - kdv = kdv.Next; - } - - return false; - } - - /// - /// Gets the keys internal. - /// - /// An ImmutableArray. - private ImmutableArray GetKeysInternal() - { - var builder = ImmutableArray.CreateBuilder(this.Count); - foreach (var value in this._internalBuckets.Values) - { - var kdv = value; - while (kdv != null) - { - builder.Add(kdv.Key); - kdv = kdv.Next; - } - } - - return builder.MoveToImmutable(); - } - - /// - /// Gets the values internal. - /// - /// An ImmutableArray. - private ImmutableArray GetValuesInternal() - { - var builder = ImmutableArray.CreateBuilder(this.Count); - foreach (var value in this._internalBuckets.Values) - { - var kdv = value; - while (kdv != null) - { - builder.Add(kdv.Value); - kdv = kdv.Next; - } - } - - return builder.MoveToImmutable(); - } - - /// - /// Prepares the items. - /// - /// The items. - /// The count. - /// An IReadOnlyDictionary. - private static IReadOnlyDictionary PrepareItems(IEnumerable> items, out int count) - { - count = 0; - var dict = new Dictionary(); - foreach (var (k, v) in items) - { - if (k == null) - throw new ArgumentException("Keys cannot be null.", nameof(items)); - - var hash = k.CalculateKnuthHash(); - if (!dict.ContainsKey(hash)) - { - dict.Add(hash, new KeyedValue(k, hash, v)); - count++; - continue; - } - - var kdv = dict[hash]; - var kdvLast = kdv; - while (kdv != null) - { - if (kdv.Key == k) - throw new ArgumentException("Given key is already present in the dictionary.", nameof(items)); - - kdvLast = kdv; - kdv = kdv.Next; - } - - kdvLast.Next = new KeyedValue(k, hash, v); - count++; - } - - return new ReadOnlyDictionary(dict); - } - - /// - /// The keyed value. - /// - private class KeyedValue - { - /// - /// Gets the key hash. - /// - public ulong KeyHash { get; } - /// - /// Gets the key. - /// - public string Key { get; } - /// - /// Gets or sets the value. - /// - public TValue Value { get; set; } - - /// - /// Gets or sets the next. - /// - public KeyedValue Next { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The key. - /// The key hash. - /// The value. - public KeyedValue(string key, ulong keyHash, TValue value) - { - this.KeyHash = keyHash; - this.Key = key; - this.Value = value; - } - } - - /// - /// The enumerator. - /// - private class Enumerator : IEnumerator> - { - /// - /// Gets the current. - /// - public KeyValuePair Current { get; private set; } - /// - /// Gets the current. - /// - object IEnumerator.Current => this.Current; - - /// - /// Gets the internal dictionary. - /// - private readonly CharSpanLookupReadOnlyDictionary _internalDictionary; - - /// - /// Gets the internal enumerator. - /// - private readonly IEnumerator> _internalEnumerator; - - /// - /// Gets or sets the current value. - /// - private KeyedValue _currentValue; - - /// - /// Initializes a new instance of the class. - /// - /// The sp dict. - public Enumerator(CharSpanLookupReadOnlyDictionary spDict) - { - this._internalDictionary = spDict; - this._internalEnumerator = this._internalDictionary._internalBuckets.GetEnumerator(); - } - - /// - /// Moves the next. - /// - /// A bool. - public bool MoveNext() - { - var kdv = this._currentValue; - if (kdv == null) - { - if (!this._internalEnumerator.MoveNext()) - return false; - - kdv = this._internalEnumerator.Current.Value; - this.Current = new KeyValuePair(kdv.Key, kdv.Value); - - this._currentValue = kdv.Next; - return true; - } - - this.Current = new KeyValuePair(kdv.Key, kdv.Value); - this._currentValue = kdv.Next; - return true; - } - - /// - /// Resets the. - /// - public void Reset() - { - this._internalEnumerator.Reset(); - this.Current = default; - this._currentValue = null; - } - - /// - /// Disposes the. - /// - public void Dispose() => this.Reset(); - } - } -} diff --git a/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs b/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs deleted file mode 100644 index d6163205b..000000000 --- a/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs +++ /dev/null @@ -1,255 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Buffers; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace DisCatSharp.Common.Types -{ - /// - /// Provides a resizable memory buffer analogous to , using a single continuous memory region instead. - /// - /// Type of item to hold in the buffer. - public sealed class ContinuousMemoryBuffer : IMemoryBuffer where T : unmanaged - { - /// - public ulong Capacity => (ulong)this._buff.Length; - - /// - public ulong Length => (ulong)this._pos; - - /// - public ulong Count => (ulong)(this._pos / this._itemSize); - - private readonly MemoryPool _pool; - private IMemoryOwner _buffOwner; - private Memory _buff; - private readonly bool _clear; - private int _pos; - private readonly int _itemSize; - private bool _isDisposed; - - /// - /// Creates a new buffer with a specified segment size, specified number of initially-allocated segments, and supplied memory pool. - /// - /// Initial size of the buffer in bytes. Defaults to 64KiB. - /// Memory pool to use for renting buffers. Defaults to . - /// Determines whether the underlying buffers should be cleared on exit. If dealing with sensitive data, it might be a good idea to set this option to true. - public ContinuousMemoryBuffer(int initialSize = 65536, MemoryPool memPool = default, bool clearOnDispose = false) - { - this._itemSize = Unsafe.SizeOf(); - this._pool = memPool ?? MemoryPool.Shared; - this._clear = clearOnDispose; - - this._buffOwner = this._pool.Rent(initialSize); - this._buff = this._buffOwner.Memory; - - this._isDisposed = false; - } - - /// - public void Write(ReadOnlySpan data) - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - var bytes = MemoryMarshal.AsBytes(data); - this.EnsureSize(this._pos + bytes.Length); - - bytes.CopyTo(this._buff[this._pos..].Span); - this._pos += bytes.Length; - } - - /// - public void Write(T[] data, int start, int count) - => this.Write(data.AsSpan(start, count)); - - /// - public void Write(ArraySegment data) - => this.Write(data.AsSpan()); - - /// - public void Write(Stream stream) - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - if (stream.CanSeek) - this.WriteStreamSeekable(stream); - else - this.WriteStreamUnseekable(stream); - } - - /// - /// Writes the stream seekable. - /// - /// The stream. - private void WriteStreamSeekable(Stream stream) - { - if (stream.Length > int.MaxValue) - throw new ArgumentException("Stream is too long.", nameof(stream)); - - this.EnsureSize(this._pos + (int)stream.Length); - var memo = ArrayPool.Shared.Rent((int)stream.Length); - try - { - var br = stream.Read(memo, 0, memo.Length); - memo.AsSpan(0, br).CopyTo(this._buff[this._pos..].Span); - } - finally - { - ArrayPool.Shared.Return(memo); - } - - this._pos += (int)stream.Length; - } - - /// - /// Writes the stream unseekable. - /// - /// The stream. - private void WriteStreamUnseekable(Stream stream) - { - var memo = ArrayPool.Shared.Rent(4096); - try - { - var br = 0; - while ((br = stream.Read(memo, 0, memo.Length)) != 0) - { - this.EnsureSize(this._pos + br); - memo.AsSpan(0, br).CopyTo(this._buff[this._pos..].Span); - this._pos += br; - } - } - finally - { - ArrayPool.Shared.Return(memo); - } - } - - /// - public bool Read(Span destination, ulong source, out int itemsWritten) - { - itemsWritten = 0; - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - source *= (ulong)this._itemSize; - if (source > this.Count) - throw new ArgumentOutOfRangeException(nameof(source), "Cannot copy data from beyond the buffer."); - - var start = (int)source; - var sbuff = this._buff[start..this._pos ].Span; - var dbuff = MemoryMarshal.AsBytes(destination); - if (sbuff.Length > dbuff.Length) - sbuff = sbuff[..dbuff.Length]; - - itemsWritten = sbuff.Length / this._itemSize; - sbuff.CopyTo(dbuff); - - return this.Length - source != (ulong)itemsWritten; - } - - /// - public bool Read(T[] data, int start, int count, ulong source, out int itemsWritten) - => this.Read(data.AsSpan(start, count), source, out itemsWritten); - - /// - public bool Read(ArraySegment data, ulong source, out int itemsWritten) - => this.Read(data.AsSpan(), source, out itemsWritten); - - /// - public T[] ToArray() - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - return MemoryMarshal.Cast(this._buff[..this._pos].Span).ToArray(); - } - - /// - public void CopyTo(Stream destination) - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - var buff = this._buff[..this._pos].ToArray(); - destination.Write(buff, 0, buff.Length); - } - - /// - public void Clear() - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - this._pos = 0; - } - - /// - /// Disposes of any resources claimed by this buffer. - /// - public void Dispose() - { - if (this._isDisposed) - return; - - this._isDisposed = true; - if (this._clear) - this._buff.Span.Clear(); - - this._buffOwner.Dispose(); - this._buff = default; - } - - /// - /// Ensures the size. - /// - /// The new capacity. - private void EnsureSize(int newCapacity) - { - var cap = this._buff.Length; - if (cap >= newCapacity) - return; - - var factor = newCapacity / cap; - if (newCapacity % cap != 0) - ++factor; - - var newActualCapacity = cap * factor; - - var newBuffOwner = this._pool.Rent(newActualCapacity); - var newBuff = newBuffOwner.Memory; - - this._buff.Span.CopyTo(newBuff.Span); - if (this._clear) - this._buff.Span.Clear(); - - this._buffOwner.Dispose(); - this._buffOwner = newBuffOwner; - this._buff = newBuff; - } - } -} diff --git a/DisCatSharp.Common/Types/IMemoryBuffer.cs b/DisCatSharp.Common/Types/IMemoryBuffer.cs deleted file mode 100644 index d498b4816..000000000 --- a/DisCatSharp.Common/Types/IMemoryBuffer.cs +++ /dev/null @@ -1,127 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.IO; - -namespace DisCatSharp.Common.Types -{ - /// - /// An interface describing the API of resizable memory buffers, such as and . - /// - /// Type of item to hold in the buffer. - public interface IMemoryBuffer : IDisposable where T : unmanaged - { - /// - /// Gets the total capacity of this buffer. The capacity is the number of segments allocated, multiplied by size of individual segment. - /// - ulong Capacity { get; } - - /// - /// Gets the amount of bytes currently written to the buffer. This number is never greater than . - /// - ulong Length { get; } - - /// - /// Gets the number of items currently written to the buffer. This number is equal to divided by size of . - /// - ulong Count { get; } - - /// - /// Appends data from a supplied buffer to this buffer, growing it if necessary. - /// - /// Buffer containing data to write. - void Write(ReadOnlySpan data); - - /// - /// Appends data from a supplied array to this buffer, growing it if necessary. - /// - /// Array containing data to write. - /// Index from which to start reading the data. - /// Number of bytes to read from the source. - void Write(T[] data, int start, int count); - - /// - /// Appends data from a supplied array slice to this buffer, growing it if necessary. - /// - /// Array slice containing data to write. - void Write(ArraySegment data); - - /// - /// Appends data from a supplied stream to this buffer, growing it if necessary. - /// - /// Stream to copy data from. - void Write(Stream stream); - - /// - /// Reads data from this buffer to the specified destination buffer. This method will write either as many - /// bytes as there are in the destination buffer, or however many bytes are available in this buffer, - /// whichever is less. - /// - /// Buffer to read the data from this buffer into. - /// Starting position in this buffer to read from. - /// Number of items written to the destination buffer. - /// Whether more data is available in this buffer. - bool Read(Span destination, ulong source, out int itemsWritten); - - /// - /// Reads data from this buffer to specified destination array. This method will write either as many bytes - /// as specified for the destination array, or however many bytes are available in this buffer, whichever is - /// less. - /// - /// Array to read the data from this buffer into. - /// Starting position in the target array to write to. - /// Maximum number of bytes to write to target array. - /// Starting position in this buffer to read from. - /// Number of items written to the destination buffer. - /// Whether more data is available in this buffer. - bool Read(T[] data, int start, int count, ulong source, out int itemsWritten); - - /// - /// Reads data from this buffer to specified destination array slice. This method will write either as many - /// bytes as specified in the target slice, or however many bytes are available in this buffer, whichever is - /// less. - /// - /// - /// - /// Number of items written to the destination buffer. - /// Whether more data is available in this buffer. - bool Read(ArraySegment data, ulong source, out int itemsWritten); - - /// - /// Converts this buffer into a single continuous byte array. - /// - /// Converted byte array. - T[] ToArray(); - - /// - /// Copies all the data from this buffer to a stream. - /// - /// Stream to copy this buffer's data to. - void CopyTo(Stream destination); - - /// - /// Resets the buffer's pointer to the beginning, allowing for reuse. - /// - void Clear(); - } -} diff --git a/DisCatSharp.Common/Types/LinqMethods.cs b/DisCatSharp.Common/Types/LinqMethods.cs index 576afe2cc..bd601cc85 100644 --- a/DisCatSharp.Common/Types/LinqMethods.cs +++ b/DisCatSharp.Common/Types/LinqMethods.cs @@ -1,79 +1,76 @@ // This file is part of the DisCatSharp project, based off DSharpPlus. // // Copyright (c) 2021-2022 AITSYS // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using System; using System.Collections.Generic; using System.Linq; namespace DisCatSharp.Common { /// /// Various Methods for Linq /// public static class LinqMethods { /// /// Safely tries to get the first match out of a list. /// /// Value type of list. /// The list to use. /// The predicate. /// The value to get if succeeded /// Whether a value was found. -#nullable enable public static bool GetFirstValueWhere(this List? list, Func predicate, out TSource? value) { - if (list == null || !list.Any()) + if (list.EmptyOrNull()) { value = default; return false; } value = list.Where(predicate).FirstOrDefault(); return value is not null; } -#nullable disable /// /// Safely tries to extract the value of the first match where target key is found, otherwise null. /// /// Key type of dictionary. /// Value type of dictionary. /// The dictionary to use. /// The key to search for. /// The value to get if succeeded. /// Whether a value was found through the key. -#nullable enable - public static bool GetFirstValueByKey(this Dictionary? dict, TKey? key, out TValue? value) + public static bool GetFirstValueByKey(this Dictionary? dict, TKey? key, out TValue? value) + where TKey : notnull { if (dict == null) { value = default; return false; } return dict.TryGetValue(key, out value); } -#nullable disable } } diff --git a/DisCatSharp.Common/Types/MemoryBuffer.cs b/DisCatSharp.Common/Types/MemoryBuffer.cs deleted file mode 100644 index aca6d3151..000000000 --- a/DisCatSharp.Common/Types/MemoryBuffer.cs +++ /dev/null @@ -1,340 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Buffers; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace DisCatSharp.Common.Types -{ - /// - /// Provides a resizable memory buffer, which can be read from and written to. It will automatically resize whenever required. - /// - /// Type of item to hold in the buffer. - public sealed class MemoryBuffer : IMemoryBuffer where T : unmanaged - { - /// - public ulong Capacity => this._segments.Aggregate(0UL, (a, x) => a + (ulong)x.Memory.Length); // .Sum() does only int - - /// - public ulong Length { get; private set; } - - /// - public ulong Count => this.Length / (ulong)this._itemSize; - - private readonly MemoryPool _pool; - private readonly int _segmentSize; - private int _lastSegmentLength; - private int _segNo; - private readonly bool _clear; - private readonly List> _segments; - private readonly int _itemSize; - private bool _isDisposed; - - /// - /// Creates a new buffer with a specified segment size, specified number of initially-allocated segments, and supplied memory pool. - /// - /// Byte size of an individual segment. Defaults to 64KiB. - /// Number of segments to allocate. Defaults to 0. - /// Memory pool to use for renting buffers. Defaults to . - /// Determines whether the underlying buffers should be cleared on exit. If dealing with sensitive data, it might be a good idea to set this option to true. - public MemoryBuffer(int segmentSize = 65536, int initialSegmentCount = 0, MemoryPool memPool = default, bool clearOnDispose = false) - { - this._itemSize = Unsafe.SizeOf(); - if (segmentSize % this._itemSize != 0) - throw new ArgumentException("Segment size must match size of individual item."); - - this._pool = memPool ?? MemoryPool.Shared; - - this._segmentSize = segmentSize; - this._segNo = 0; - this._lastSegmentLength = 0; - this._clear = clearOnDispose; - - this._segments = new List>(initialSegmentCount + 1); - for (var i = 0; i < initialSegmentCount; i++) - this._segments.Add(this._pool.Rent(this._segmentSize)); - - this.Length = 0; - - this._isDisposed = false; - } - - /// - public void Write(ReadOnlySpan data) - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - var src = MemoryMarshal.AsBytes(data); - this.Grow(src.Length); - - while (this._segNo < this._segments.Count && src.Length > 0) - { - var seg = this._segments[this._segNo]; - var mem = seg.Memory; - var avs = mem.Length - this._lastSegmentLength; - avs = avs > src.Length - ? src.Length - : avs; - var dmem = mem[this._lastSegmentLength..]; - - src[..avs].CopyTo(dmem.Span); - src = src[avs..]; - - this.Length += (ulong)avs; - this._lastSegmentLength += avs; - - if (this._lastSegmentLength == mem.Length) - { - this._segNo++; - this._lastSegmentLength = 0; - } - } - } - - /// - public void Write(T[] data, int start, int count) - => this.Write(data.AsSpan(start, count)); - - /// - public void Write(ArraySegment data) - => this.Write(data.AsSpan()); - - /// - public void Write(Stream stream) - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - if (stream.CanSeek) - this.WriteStreamSeekable(stream); - else - this.WriteStreamUnseekable(stream); - } - - /// - /// Writes the stream seekable. - /// - /// The stream. - private void WriteStreamSeekable(Stream stream) - { - var len = (int)(stream.Length - stream.Position); - this.Grow(len); - - var buff = new byte[this._segmentSize]; - - while (this._segNo < this._segments.Count && len > 0) - { - var seg = this._segments[this._segNo]; - var mem = seg.Memory; - var avs = mem.Length - this._lastSegmentLength; - avs = avs > len - ? len - : avs; - var dmem = mem[this._lastSegmentLength..]; - - var lsl = this._lastSegmentLength; - var slen = dmem.Span.Length - lsl; - stream.Read(buff, 0, slen); - buff.AsSpan(0, slen).CopyTo(dmem.Span); - len -= dmem.Span.Length; - - this.Length += (ulong)avs; - this._lastSegmentLength += avs; - - if (this._lastSegmentLength == mem.Length) - { - this._segNo++; - this._lastSegmentLength = 0; - } - } - } - - /// - /// Writes the stream unseekable. - /// - /// The stream. - private void WriteStreamUnseekable(Stream stream) - { - var read = 0; - var buff = new byte[this._segmentSize]; - var buffs = buff.AsSpan(); - while ((read = stream.Read(buff, 0, buff.Length - this._lastSegmentLength)) != 0) - this.Write(MemoryMarshal.Cast(buffs[..read])); - } - - /// - public bool Read(Span destination, ulong source, out int itemsWritten) - { - itemsWritten = 0; - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - source *= (ulong)this._itemSize; - if (source > this.Count) - throw new ArgumentOutOfRangeException(nameof(source), "Cannot copy data from beyond the buffer."); - - // Find where to begin - var i = 0; - for (; i < this._segments.Count; i++) - { - var seg = this._segments[i]; - var mem = seg.Memory; - if ((ulong)mem.Length > source) - break; - - source -= (ulong)mem.Length; - } - - // Do actual copy - var dl = (int)(this.Length - source); - var sri = (int)source; - var dst = MemoryMarshal.AsBytes(destination); - for (; i < this._segments.Count && dst.Length > 0; i++) - { - var seg = this._segments[i]; - var mem = seg.Memory; - var src = mem.Span; - - if (sri != 0) - { - src = src[sri..]; - sri = 0; - } - - if (itemsWritten + src.Length > dl) - src = src[..(dl - itemsWritten)]; - - if (src.Length > dst.Length) - src = src[..dst.Length]; - - src.CopyTo(dst); - dst = dst[src.Length..]; - itemsWritten += src.Length; - } - - itemsWritten /= this._itemSize; - return this.Length - source != (ulong)itemsWritten; - } - - /// - public bool Read(T[] data, int start, int count, ulong source, out int itemsWritten) - => this.Read(data.AsSpan(start, count), source, out itemsWritten); - - /// - public bool Read(ArraySegment data, ulong source, out int itemsWritten) - => this.Read(data.AsSpan(), source, out itemsWritten); - - /// - public T[] ToArray() - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - var bytes = new T[this.Count]; - this.Read(bytes, 0, out _); - return bytes; - } - - /// - public void CopyTo(Stream destination) - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - var longest = this._segments.Max(x => x.Memory.Length); - var buff = new byte[longest]; - - foreach (var seg in this._segments) - { - var mem = seg.Memory.Span; - var spn = buff.AsSpan(0, mem.Length); - - mem.CopyTo(spn); - destination.Write(buff, 0, spn.Length); - } - } - - /// - public void Clear() - { - if (this._isDisposed) - throw new ObjectDisposedException("This buffer is disposed."); - - this._segNo = 0; - this._lastSegmentLength = 0; - this.Length = 0; - } - - /// - /// Disposes of any resources claimed by this buffer. - /// - public void Dispose() - { - if (this._isDisposed) - return; - - this._isDisposed = true; - foreach (var segment in this._segments) - { - if (this._clear) - segment.Memory.Span.Clear(); - - segment.Dispose(); - } - } - - /// - /// Grows the. - /// - /// The min amount. - private void Grow(int minAmount) - { - var capacity = this.Capacity; - var length = this.Length; - var totalAmt = length + (ulong)minAmount; - if (capacity >= totalAmt) - return; // we're good - - var amt = (int)(totalAmt - capacity); - var segCount = amt / this._segmentSize; - if (amt % this._segmentSize != 0) - segCount++; - - // Basically List.EnsureCapacity - // Default grow behaviour is minimum current*2 - var segCap = this._segments.Count + segCount; - if (segCap > this._segments.Capacity) - this._segments.Capacity = segCap < this._segments.Capacity * 2 - ? this._segments.Capacity * 2 - : segCap; - - for (var i = 0; i < segCount; i++) - this._segments.Add(this._pool.Rent(this._segmentSize)); - } - } -} diff --git a/DisCatSharp.Common/Types/SecureRandom.cs b/DisCatSharp.Common/Types/SecureRandom.cs deleted file mode 100644 index 6daf056b9..000000000 --- a/DisCatSharp.Common/Types/SecureRandom.cs +++ /dev/null @@ -1,331 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Buffers; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security.Cryptography; - -namespace DisCatSharp.Common -{ - /// - /// Provides a cryptographically-secure pseudorandom number generator (CSPRNG) implementation compatible with . - /// - public sealed class SecureRandom : Random, IDisposable - { - /// - /// Gets the r n g. - /// - private readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create(); - - private volatile bool _isDisposed; - - /// - /// Creates a new instance of . - /// - public SecureRandom() - { } - - /// - /// Finalizes this instance by disposing it. - /// - ~SecureRandom() - { - this.Dispose(); - } - - /// - /// Fills a supplied buffer with random bytes. - /// - /// Buffer to fill with random bytes. - public void GetBytes(byte[] buffer) => this._rng.GetBytes(buffer); - - /// - /// Fills a supplied buffer with random nonzero bytes. - /// - /// Buffer to fill with random nonzero bytes. - public void GetNonZeroBytes(byte[] buffer) => this._rng.GetNonZeroBytes(buffer); - - /// - /// Fills a supplied memory region with random bytes. - /// - /// Memory region to fill with random bytes. - public void GetBytes(Span buffer) - { - var buff = ArrayPool.Shared.Rent(buffer.Length); - try - { - var buffSpan = buff.AsSpan(0, buffer.Length); - this._rng.GetBytes(buff); - buffSpan.CopyTo(buffer); - } - finally - { - ArrayPool.Shared.Return(buff); - } - } - - /// - /// Fills a supplied memory region with random nonzero bytes. - /// - /// Memory region to fill with random nonzero bytes. - public void GetNonZeroBytes(Span buffer) - { - var buff = ArrayPool.Shared.Rent(buffer.Length); - try - { - var buffSpan = buff.AsSpan(0, buffer.Length); - this._rng.GetNonZeroBytes(buff); - buffSpan.CopyTo(buffer); - } - finally - { - ArrayPool.Shared.Return(buff); - } - } - - /// - /// Generates a signed 8-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public sbyte GetInt8(sbyte min = 0, sbyte max = sbyte.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - var offset = (sbyte)(min < 0 ? -min : 0); - min += offset; - max += offset; - - return (sbyte)(Math.Abs(this.Generate()) % (max - min) + min - offset); - } - - /// - /// Generates a unsigned 8-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public byte GetUInt8(byte min = 0, byte max = byte.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - return (byte)(this.Generate() % (max - min) + min); - } - - /// - /// Generates a signed 16-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public short GetInt16(short min = 0, short max = short.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - var offset = (short)(min < 0 ? -min : 0); - min += offset; - max += offset; - - return (short)(Math.Abs(this.Generate()) % (max - min) + min - offset); - } - - /// - /// Generates a unsigned 16-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public ushort GetUInt16(ushort min = 0, ushort max = ushort.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - return (ushort)(this.Generate() % (max - min) + min); - } - - /// - /// Generates a signed 32-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public int GetInt32(int min = 0, int max = int.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - var offset = min < 0 ? -min : 0; - min += offset; - max += offset; - - return Math.Abs(this.Generate()) % (max - min) + min - offset; - } - - /// - /// Generates a unsigned 32-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public uint GetUInt32(uint min = 0, uint max = uint.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - return this.Generate() % (max - min) + min; - } - - /// - /// Generates a signed 64-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public long GetInt64(long min = 0, long max = long.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - var offset = min < 0 ? -min : 0; - min += offset; - max += offset; - - return Math.Abs(this.Generate()) % (max - min) + min - offset; - } - - /// - /// Generates a unsigned 64-bit integer within specified range. - /// - /// Minimum value to generate. Defaults to 0. - /// Maximum value to generate. Defaults to . - /// Generated random value. - public ulong GetUInt64(ulong min = 0, ulong max = ulong.MaxValue) - { - if (max <= min) - throw new ArgumentException("Maximum needs to be greater than minimum.", nameof(max)); - - return this.Generate() % (max - min) + min; - } - - /// - /// Generates a 32-bit floating-point number between 0.0 and 1.0. - /// - /// Generated 32-bit floating-point number. - public float GetSingle() - { - var (i1, i2) = ((float)this.GetInt32(), (float)this.GetInt32()); - return i1 / i2 % 1.0F; - } - - /// - /// Generates a 64-bit floating-point number between 0.0 and 1.0. - /// - /// Generated 64-bit floating-point number. - public double GetDouble() - { - var (i1, i2) = ((double)this.GetInt64(), (double)this.GetInt64()); - return i1 / i2 % 1.0; - } - - /// - /// Generates a 32-bit integer between 0 and . Upper end exclusive. - /// - /// Generated 32-bit integer. - public override int Next() - => this.GetInt32(); - - /// - /// Generates a 32-bit integer between 0 and . Upper end exclusive. - /// - /// Maximum value of the generated integer. - /// Generated 32-bit integer. - public override int Next(int maxValue) - => this.GetInt32(0, maxValue); - - /// - /// Generates a 32-bit integer between and . Upper end exclusive. - /// - /// Minimum value of the generate integer. - /// Maximum value of the generated integer. - /// Generated 32-bit integer. - public override int Next(int minValue, int maxValue) - => this.GetInt32(minValue, maxValue); - - /// - /// Generates a 64-bit floating-point number between 0.0 and 1.0. Upper end exclusive. - /// - /// Generated 64-bit floating-point number. - public override double NextDouble() - => this.GetDouble(); - - /// - /// Fills specified buffer with random bytes. - /// - /// Buffer to fill with bytes. - public override void NextBytes(byte[] buffer) - => this.GetBytes(buffer); - - /// - /// Fills specified memory region with random bytes. - /// - /// Memory region to fill with bytes. - public new void NextBytes(Span buffer) - => this.GetBytes(buffer); - - /// - /// Disposes this instance and its resources. - /// - public void Dispose() - { - if (this._isDisposed) - return; - - this._isDisposed = true; - this._rng.Dispose(); - } - - /// - /// Generates a random 64-bit floating-point number between 0.0 and 1.0. Upper end exclusive. - /// - /// Generated 64-bit floating-point number. - protected override double Sample() - => this.GetDouble(); - - /// - /// Generates the. - /// - /// A T. - private T Generate() where T : struct - { - var size = Unsafe.SizeOf(); - Span buff = stackalloc byte[size]; - this.GetBytes(buff); - return MemoryMarshal.Read(buff); - } - } -} diff --git a/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs b/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs deleted file mode 100644 index 0878380cd..000000000 --- a/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Decomposes numbers into tuples (arrays of 2). - /// - public sealed class ComplexDecomposer : IDecomposer - { - /// - /// Gets the t complex. - /// - private static Type s_complex { get; } = typeof(Complex); - /// - /// Gets the t double array. - /// - private static Type s_doubleArray { get; } = typeof(double[]); - /// - /// Gets the t double enumerable. - /// - private static Type s_doubleEnumerable { get; } = typeof(IEnumerable); - /// - /// Gets the t object array. - /// - private static Type s_objectArray { get; } = typeof(object[]); - /// - /// Gets the t object enumerable. - /// - private static Type s_objectEnumerable { get; } = typeof(IEnumerable); - - /// - public bool CanDecompose(Type t) - => t == s_complex; - - /// - public bool CanRecompose(Type t) - => t == s_doubleArray - || t == s_objectArray - || s_doubleEnumerable.IsAssignableFrom(t) - || s_objectEnumerable.IsAssignableFrom(t); - - /// - public bool TryDecompose(object obj, Type tobj, out object decomposed, out Type tdecomposed) - { - decomposed = null; - tdecomposed = s_doubleArray; - - if (tobj != s_complex || obj is not Complex c) - return false; - - decomposed = new[] { c.Real, c.Imaginary }; - return true; - } - - /// - public bool TryRecompose(object obj, Type tobj, Type trecomposed, out object recomposed) - { - recomposed = null; - - if (trecomposed != s_complex) - return false; - - // ie - if (s_doubleEnumerable.IsAssignableFrom(tobj) && obj is IEnumerable ied) - { - if (!ied.TryFirstTwo(out var values)) - return false; - - var (real, imag) = values; - recomposed = new Complex(real, imag); - return true; - } - - // ie - if (s_objectEnumerable.IsAssignableFrom(tobj) && obj is IEnumerable ieo) - { - if (!ieo.TryFirstTwo(out var values)) - return false; - - var (real, imag) = values; - if (real is not double dreal || imag is not double dimag) - return false; - - recomposed = new Complex(dreal, dimag); - return true; - } - - return false; - } - } -} diff --git a/DisCatSharp.Common/Types/Serialization/IDecomposer.cs b/DisCatSharp.Common/Types/Serialization/IDecomposer.cs deleted file mode 100644 index e419f9d06..000000000 --- a/DisCatSharp.Common/Types/Serialization/IDecomposer.cs +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; - -namespace DisCatSharp.Common.Serialization -{ - /// - /// Provides an interface to decompose an object into another object or combination of objects. - /// - public interface IDecomposer - { - /// - /// Checks whether the decomposer can decompose a specific type. - /// - /// Type to check. - /// Whether the decomposer can decompose a given type. - bool CanDecompose(Type t); - - /// - /// Checks whether the decomposer can recompose a specific decomposed type. - /// Note that while a type might be considered recomposable, other factors might prevent recomposing operation from being successful. - /// - /// Decomposed type to check. - /// Whether the decomposer can decompose a given type. - bool CanRecompose(Type t); - - /// - /// Attempts to decompose a given object of specified source type. The operation produces the decomposed object and the type it got decomposed into. - /// - /// Object to decompose. - /// Type to decompose. - /// Decomposition result. - /// Type of the result. - /// Whether the operation was successful. - bool TryDecompose(object obj, Type tobj, out object decomposed, out Type tdecomposed); - - /// - /// Attempts to recompose given object of specified source type, into specified target type. The operation produces the recomposed object. - /// - /// Object to recompose from. - /// Type of data to recompose. - /// Type to recompose into. - /// Recomposition result. - /// Whether the operation was successful. - bool TryRecompose(object obj, Type tobj, Type trecomposed, out object recomposed); - } -} diff --git a/DisCatSharp.Common/Utilities/AsyncExecutor.cs b/DisCatSharp.Common/Utilities/AsyncExecutor.cs deleted file mode 100644 index 6f9101f4b..000000000 --- a/DisCatSharp.Common/Utilities/AsyncExecutor.cs +++ /dev/null @@ -1,173 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace DisCatSharp.Common.Utilities -{ - /// - /// Provides a simplified way of executing asynchronous code synchronously. - /// - public class AsyncExecutor - { - /// - /// Creates a new instance of asynchronous executor. - /// - public AsyncExecutor() - { } - - /// - /// Executes a specified task in an asynchronous manner, waiting for its completion. - /// - /// Task to execute. - public void Execute(Task task) - { - // create state object - var taskState = new StateRef(new AutoResetEvent(false)); - - // queue a task and wait for it to finish executing - task.ContinueWith(TaskCompletionHandler, taskState); - taskState.Lock.WaitOne(); - - // check for and rethrow any exceptions - if (taskState.Exception != null) - throw taskState.Exception; - - // completion method - void TaskCompletionHandler(Task t, object state) - { - // retrieve state data - var stateRef = state as StateRef; - - // retrieve any exceptions or cancellation status - if (t.IsFaulted) - { - if (t.Exception.InnerExceptions.Count == 1) // unwrap if 1 - stateRef.Exception = t.Exception.InnerException; - else - stateRef.Exception = t.Exception; - } - else if (t.IsCanceled) - { - stateRef.Exception = new TaskCanceledException(t); - } - - // signal that the execution is done - stateRef.Lock.Set(); - } - } - - /// - /// Executes a specified task in an asynchronous manner, waiting for its completion, and returning the result. - /// - /// Type of the Task's return value. - /// Task to execute. - /// Task's result. - public T Execute(Task task) - { - // create state object - var taskState = new StateRef(new AutoResetEvent(false)); - - // queue a task and wait for it to finish executing - task.ContinueWith(TaskCompletionHandler, taskState); - taskState.Lock.WaitOne(); - - // check for and rethrow any exceptions - if (taskState.Exception != null) - throw taskState.Exception; - - // return the result, if any - if (taskState.HasResult) - return taskState.Result; - - // throw exception if no result - throw new Exception("Task returned no result."); - - // completion method - void TaskCompletionHandler(Task t, object state) - { - // retrieve state data - var stateRef = state as StateRef; - - // retrieve any exceptions or cancellation status - if (t.IsFaulted) - { - if (t.Exception.InnerExceptions.Count == 1) // unwrap if 1 - stateRef.Exception = t.Exception.InnerException; - else - stateRef.Exception = t.Exception; - } - else if (t.IsCanceled) - { - stateRef.Exception = new TaskCanceledException(t); - } - - // return the result from the task, if any - if (t.IsCompleted && !t.IsFaulted) - { - stateRef.HasResult = true; - stateRef.Result = t.Result; - } - - // signal that the execution is done - stateRef.Lock.Set(); - } - } - - /// - /// The state ref. - /// - private sealed class StateRef - { - /// - /// Gets the lock used to wait for task's completion. - /// - public AutoResetEvent Lock { get; } - - /// - /// Gets the exception that occurred during task's execution, if any. - /// - public Exception Exception { get; set; } - - /// - /// Gets the result returned by the task. - /// - public T Result { get; set; } - - /// - /// Gets whether the task returned a result. - /// - public bool HasResult { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The lock. - public StateRef(AutoResetEvent @lock) - { - this.Lock = @lock; - } - } - } -} diff --git a/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs b/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs deleted file mode 100644 index c15e09956..000000000 --- a/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs +++ /dev/null @@ -1,81 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System.Threading; -using System.Threading.Tasks; - -namespace DisCatSharp.Common.Utilities -{ - /// - /// Represents a thread synchronization event that, when signaled, must be reset manually. Unlike , this event is asynchronous. - /// - public sealed class AsyncManualResetEvent - { - /// - /// Gets whether this event has been signaled. - /// - public bool IsSet => this._resetTcs?.Task?.IsCompleted == true; - - private volatile TaskCompletionSource _resetTcs; - - /// - /// Creates a new asynchronous synchronization event with initial state. - /// - /// Initial state of this event. - public AsyncManualResetEvent(bool initialState) - { - this._resetTcs = new TaskCompletionSource(); - if (initialState) - this._resetTcs.TrySetResult(initialState); - } - - // Spawn a threadpool thread instead of making a task - // Maybe overkill, but I am less unsure of this than awaits and - // potentially cross-scheduler interactions - /// - /// Asynchronously signal this event. - /// - /// - public Task SetAsync() - => Task.Run(() => this._resetTcs.TrySetResult(true)); - - /// - /// Asynchronously wait for this event to be signaled. - /// - /// - public Task WaitAsync() - => this._resetTcs.Task; - - /// - /// Reset this event's signal state to unsignaled. - /// - public void Reset() - { - while (true) - { - var tcs = this._resetTcs; - if (!tcs.Task.IsCompleted || Interlocked.CompareExchange(ref this._resetTcs, new TaskCompletionSource(), tcs) == tcs) - return; - } - } - } -} diff --git a/DisCatSharp.Common/Utilities/EnsureObjectStates.cs b/DisCatSharp.Common/Utilities/EnsureObjectStates.cs index d781fdb92..85a2b2cb4 100644 --- a/DisCatSharp.Common/Utilities/EnsureObjectStates.cs +++ b/DisCatSharp.Common/Utilities/EnsureObjectStates.cs @@ -1,79 +1,71 @@ // This file is part of the DisCatSharp project, based off DSharpPlus. // // Copyright (c) 2021-2022 AITSYS // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using System.Collections.Generic; using System.Linq; namespace DisCatSharp.Common { /// /// Ensures that certain objects have the target state. /// public static class EnsureObjectStates { /// /// Checks whether the dictionary is null or empty. /// /// Any key type. /// Any value type. /// The dictionary to check on. /// True if satisfied, false otherwise. -#nullable enable - public static bool EmptyOrNull(this Dictionary? dictionary) - => dictionary == null || !dictionary.Any() || dictionary.Keys == null || !dictionary.Keys.Any(); -#nullable disable + public static bool EmptyOrNull(this Dictionary? dictionary) where T1 : notnull + => dictionary == null || !dictionary.Any() || !dictionary.Keys.Any(); /// /// Checks whether the dictionary is not null and not empty. /// /// Any key type. /// Any value type. /// The dictionary to check on. /// True if satisfied, false otherwise. -#nullable enable - public static bool NotEmptyAndNotNull(this Dictionary? dictionary) - => dictionary != null && dictionary.Any() && dictionary.Keys != null && dictionary.Keys.Any(); -#nullable disable + public static bool NotEmptyAndNotNull(this Dictionary? dictionary) where T1 : notnull + => dictionary != null && dictionary.Any() && dictionary.Keys.Any(); /// /// Checks whether the list is null or empty. /// /// Any value type. /// The list to check on. /// True if satisfied, false otherwise. -#nullable enable public static bool EmptyOrNull(this List? list) => list == null || !list.Any(); -#nullable disable /// /// Checks whether the list is not null and not empty. /// /// Any value type. /// The list to check on. /// True if satisfied, false otherwise. -#nullable enable public static bool NotEmptyAndNotNull(this List? list) => list != null && list.Any(); -#nullable disable } } diff --git a/DisCatSharp.Common/Utilities/Extensions.cs b/DisCatSharp.Common/Utilities/Extensions.cs deleted file mode 100644 index b7c97298c..000000000 --- a/DisCatSharp.Common/Utilities/Extensions.cs +++ /dev/null @@ -1,495 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace DisCatSharp.Common -{ - /// - /// Assortment of various extension and utility methods, designed to make working with various types a little easier. - /// - public static class Extensions - { - /// - /// Deconstructs a key-value pair item () into 2 separate variables. - /// This allows for enumerating over dictionaries in foreach blocks by using a (k, v) tuple as the enumerator variable, instead of having to use a directly. - /// - /// Type of dictionary item key. - /// Type of dictionary item value. - /// Key-value pair to deconstruct. - /// Deconstructed key. - /// Deconstructed value. - public static void Deconstruct(this KeyValuePair kvp, out TKey key, out TValue value) - { - key = kvp.Key; - value = kvp.Value; - } - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this sbyte num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(num == sbyte.MinValue ? num + 1 : num))) + (num < 0 ? 2 /* include sign */ : 1); - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this byte num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(num)) + 1; - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this short num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(num == short.MinValue ? num + 1 : num))) + (num < 0 ? 2 /* include sign */ : 1); - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this ushort num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(num)) + 1; - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this int num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(num == int.MinValue ? num + 1 : num))) + (num < 0 ? 2 /* include sign */ : 1); - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this uint num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(num)) + 1; - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this long num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(num == long.MinValue ? num + 1 : num))) + (num < 0 ? 2 /* include sign */ : 1); - - /// - /// Calculates the length of string representation of given number in base 10 (including sign, if present). - /// - /// Number to calculate the length of. - /// Calculated number length. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CalculateLength(this ulong num) - => num == 0 ? 1 : (int)Math.Floor(Math.Log10(num)) + 1; - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this sbyte num, sbyte min, sbyte max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this byte num, byte min, byte max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this short num, short min, short max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this ushort num, ushort min, ushort max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this int num, int min, int max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this uint num, uint min, uint max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this long num, long min, long max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this ulong num, ulong min, ulong max, bool inclusive = true) - { - if (min > max) - { - min ^= max; - max ^= min; - min ^= max; - } - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this float num, float min, float max, bool inclusive = true) - { - if (min > max) - return false; - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Tests whether given value is in supplied range, optionally allowing it to be an exclusive check. - /// - /// Number to test. - /// Lower bound of the range. - /// Upper bound of the range. - /// Whether the check is to be inclusive. - /// Whether the value is in range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRange(this double num, double min, double max, bool inclusive = true) - { - if (min > max) - return false; - - return inclusive ? num >= min && num <= max : num > min && num < max; - } - - /// - /// Returns whether supplied character is in any of the following ranges: a-z, A-Z, 0-9. - /// - /// Character to test. - /// Whether the character is in basic alphanumeric character range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsBasicAlphanumeric(this char c) - => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); - - /// - /// Returns whether supplied character is in the 0-9 range. - /// - /// Character to test. - /// Whether the character is in basic numeric digit character range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsBasicDigit(this char c) - => c >= '0' && c <= '9'; - - /// - /// Returns whether supplied character is in the a-z or A-Z range. - /// - /// Character to test. - /// Whether the character is in basic letter character range. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsBasicLetter(this char c) - => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); - - /// - /// Tests whether given string ends with given character. - /// - /// String to test. - /// Character to test for. - /// Whether the supplied string ends with supplied character. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool EndsWithCharacter(this string s, char c) - => s.Length >= 1 && s[^1] == c; - - /// - /// Tests whether given string starts with given character. - /// - /// String to test. - /// Character to test for. - /// Whether the supplied string starts with supplied character. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool StartsWithCharacter(this string s, char c) - => s.Length >= 1 && s[0] == c; - - // https://stackoverflow.com/questions/9545619/a-fast-hash-function-for-string-in-c-sharp - // Calls are inlined to call the underlying method directly - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this ReadOnlySpan chars) - => Knuth(chars); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this Span chars) - => Knuth(chars); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this ReadOnlyMemory chars) - => Knuth(chars.Span); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this Memory chars) - => Knuth(chars.Span); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this ArraySegment chars) - => Knuth(chars.AsSpan()); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this char[] chars) - => Knuth(chars.AsSpan()); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Offset in the array to start calculating from. - /// Number of characters to compute the hash from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this char[] chars, int start, int count) - => Knuth(chars.AsSpan(start, count)); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this string chars) - => Knuth(chars.AsSpan()); - - /// - /// Computes a 64-bit Knuth hash from supplied characters. - /// - /// Characters to compute the hash value from. - /// Offset in the array to start calculating from. - /// Number of characters to compute the hash from. - /// Computer 64-bit Knuth hash. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong CalculateKnuthHash(this string chars, int start, int count) - => Knuth(chars.AsSpan(start, count)); - - /// - /// Gets the two first elements of the , if they exist. - /// - /// The enumerable. - /// The output values. Undefined if false is returned. - /// Whether the contained enough elements. - internal static bool TryFirstTwo(this IEnumerable enumerable, out (T first, T second) values) - { - values = default; - - using var enumerator = enumerable.GetEnumerator(); - - if (!enumerator.MoveNext()) - return false; - - var first = enumerator.Current; - - if (!enumerator.MoveNext()) - return false; - - - values = (first, enumerator.Current); - return true; - } - - /// - /// Knuths the. - /// - /// The chars. - /// An ulong. - private static ulong Knuth(ReadOnlySpan chars) - { - var hash = 3074457345618258791ul; - for (var i = 0; i < chars.Length; i++) - hash = (hash + chars[i]) * 3074457345618258799ul; - return hash; - } - } -} diff --git a/DisCatSharp.Common/Utilities/ReflectionUtilities.cs b/DisCatSharp.Common/Utilities/ReflectionUtilities.cs deleted file mode 100644 index 8208228bd..000000000 --- a/DisCatSharp.Common/Utilities/ReflectionUtilities.cs +++ /dev/null @@ -1,75 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; - -namespace DisCatSharp.Common.Utilities -{ - /// - /// Contains various utilities for use with .NET's reflection. - /// - public static class ReflectionUtilities - { - /// - /// Creates an empty, uninitialized instance of specified type. - /// This method will not call the constructor for the specified type. As such, the object might not be properly initialized. - /// - /// - /// This method is intended for reflection use only. - /// - /// Type of the object to instantiate. - /// Empty, uninitialized object of specified type. - public static object CreateEmpty(this Type t) - => FormatterServices.GetUninitializedObject(t); - - /// - /// Creates an empty, uninitialized instance of type . - /// This method will not call the constructor for type . As such, the object might not be properly initialized. - /// - /// - /// This method is intended for reflection use only. - /// - /// Type of the object to instantiate. - /// Empty, uninitialized object of specified type. - public static T CreateEmpty() - => (T)FormatterServices.GetUninitializedObject(typeof(T)); - - /// - /// Converts a given object into a dictionary of property name to property value mappings. - /// - /// Type of object to convert. - /// Object to convert. - /// Converted dictionary. - public static IReadOnlyDictionary ToDictionary(this T obj) - { - if (obj == null) - throw new NullReferenceException(); - - return new CharSpanLookupReadOnlyDictionary(typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance) - .Select(x => new KeyValuePair(x.Name, x.GetValue(obj)))); - } - } -} diff --git a/DisCatSharp.Common/Utilities/RuntimeInformation.cs b/DisCatSharp.Common/Utilities/RuntimeInformation.cs deleted file mode 100644 index 3aeebe8ff..000000000 --- a/DisCatSharp.Common/Utilities/RuntimeInformation.cs +++ /dev/null @@ -1,78 +0,0 @@ -// This file is part of the DisCatSharp project, based off DSharpPlus. -// -// Copyright (c) 2021-2022 AITSYS -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace DisCatSharp.Common.Utilities -{ - /// - /// Gets information about current runtime. - /// - public static class RuntimeInformation - { - /// - /// Gets the current runtime's version. - /// - public static string Version { get; } - - /// - /// Initializes a new instance of the class. - /// - static RuntimeInformation() - { - var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - var mscorlib = loadedAssemblies.Select(x => new { Assembly = x, AssemblyName = x.GetName() }) - .FirstOrDefault(x => x.AssemblyName.Name == "mscorlib" || x.AssemblyName.Name == "System.Private.CoreLib"); - - var location = mscorlib.Assembly.Location; - var assemblyFile = new FileInfo(location); - var versionFile = new FileInfo(Path.Combine(assemblyFile.Directory.FullName, ".version")); - if (versionFile.Exists) - { - var lines = File.ReadAllLines(versionFile.FullName, new UTF8Encoding(false)); - - if (lines.Length >= 2) - { - Version = lines[1]; - return; - } - } - - var infVersion = mscorlib.Assembly.GetCustomAttribute(); - if (infVersion != null) - { - var infVersionString = infVersion.InformationalVersion; - if (!string.IsNullOrWhiteSpace(infVersionString)) - { - Version = infVersionString.Split(' ').First(); - return; - } - } - - Version = mscorlib.AssemblyName.Version.ToString(); - } - } -}