From ee7b572f2f351755086f3b5b821d67077cdb405a Mon Sep 17 00:00:00 2001 From: Oleg Rakhmatulin Date: Tue, 20 Dec 2022 06:58:53 +0100 Subject: [PATCH] Reformat most of helpers code using C# 11 new features. --- DateTimeOnly.Tests/ArgumentValidationTests.cs | 18 +- DateTimeOnly.Tests/DateOnlyTests.cs | 2 + .../FastStrictParsingLogicTests.cs | 14 +- DateTimeOnly.Tests/Helpers/ConditionalFact.cs | 5 +- .../Helpers/ConditionalFactDiscoverer.cs | 16 +- DateTimeOnly.Tests/Helpers/DateTime.cs | 8 +- DateTimeOnly.Tests/Helpers/SkippedTestCase.cs | 25 +- DateTimeOnly.Tests/TimeOnlyTests.cs | 2 + DateTimeOnly.sln.DotSettings | 3 + DateTimeOnly/DateOnly.cs | 8 +- DateTimeOnly/Helpers/DateTime.cs | 131 +++-- DateTimeOnly/Helpers/DateTimeFormat.cs | 485 +++++++++--------- DateTimeOnly/Helpers/DateTimeParse.cs | 142 ++--- DateTimeOnly/Helpers/ExceptionArgument.cs | 13 +- DateTimeOnly/Helpers/IParsable.cs | 29 +- DateTimeOnly/Helpers/ISpanParsable.cs | 29 +- DateTimeOnly/Helpers/NullableAttributes.cs | 63 +-- DateTimeOnly/Helpers/SR.cs | 53 +- DateTimeOnly/Helpers/SpanAction.cs | 7 +- DateTimeOnly/Helpers/StringFactory.cs | 20 +- DateTimeOnly/Helpers/StringSyntaxAttribute.cs | 47 +- DateTimeOnly/Helpers/ThrowHelper.cs | 45 +- DateTimeOnly/ISpanFormattable.cs | 2 + DateTimeOnly/TimeOnly.cs | 8 +- 24 files changed, 580 insertions(+), 595 deletions(-) diff --git a/DateTimeOnly.Tests/ArgumentValidationTests.cs b/DateTimeOnly.Tests/ArgumentValidationTests.cs index 79058aa..5283b22 100644 --- a/DateTimeOnly.Tests/ArgumentValidationTests.cs +++ b/DateTimeOnly.Tests/ArgumentValidationTests.cs @@ -5,24 +5,24 @@ namespace System.Tests { public sealed class ArgumentValidationTests { - private const String InputArgumentName = "s"; + private const string InputArgumentName = "s"; - private const String StyleArgumentName = "style"; + private const string StyleArgumentName = "style"; - private const String FormatArgumentName = "format"; + private const string FormatArgumentName = "format"; private static readonly DateOnly DateOnlyValue = new (); - private static readonly String DateOnlyStringValue = DateOnlyValue.ToString(); + private static readonly string DateOnlyStringValue = DateOnlyValue.ToString(); private static readonly TimeOnly TimeOnlyValue = new (); - private static readonly String TimeOnlyStringValue = TimeOnlyValue.ToString(); + private static readonly string TimeOnlyStringValue = TimeOnlyValue.ToString(); #pragma warning disable CS8625 - private static readonly String NullString = null; + private static readonly string NullString = null; - private static readonly String[] NullStringArray = null; + private static readonly string[] NullStringArray = null; #pragma warning restore CS8625 [Fact] @@ -91,7 +91,7 @@ public void DateOnlyParseExactValidationWorkedTest() () => DateOnly.ParseExact(string.Empty, NullStringArray, CultureInfo.InvariantCulture)).ParamName); Assert.Throws(() => DateOnly.ParseExact( - string.Empty, new []{ String.Empty }, CultureInfo.InvariantCulture)); + string.Empty, new []{ string.Empty }, CultureInfo.InvariantCulture)); } [Fact] @@ -209,7 +209,7 @@ public void TimeOnlyParseExactValidationWorkedTest() () => TimeOnly.ParseExact(string.Empty, NullStringArray, CultureInfo.InvariantCulture)).ParamName); Assert.Throws(() => TimeOnly.ParseExact( - string.Empty, new []{ String.Empty }, CultureInfo.InvariantCulture)); + string.Empty, new []{ string.Empty }, CultureInfo.InvariantCulture)); } [Fact] diff --git a/DateTimeOnly.Tests/DateOnlyTests.cs b/DateTimeOnly.Tests/DateOnlyTests.cs index 38125c0..6693fcd 100644 --- a/DateTimeOnly.Tests/DateOnlyTests.cs +++ b/DateTimeOnly.Tests/DateOnlyTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// ReSharper disable All + using System.Collections.Generic; using System.Globalization; using Xunit; diff --git a/DateTimeOnly.Tests/FastStrictParsingLogicTests.cs b/DateTimeOnly.Tests/FastStrictParsingLogicTests.cs index 5164435..a47c1e7 100644 --- a/DateTimeOnly.Tests/FastStrictParsingLogicTests.cs +++ b/DateTimeOnly.Tests/FastStrictParsingLogicTests.cs @@ -38,9 +38,9 @@ public static void DateTimeMinValueDateOnlyParseWorkedTest() => public static void DateTimeMinValueTimeOnlyParseWorkedTest() => RunInFastParsingLogicContext(TimeOnlyParseWorked,DateTime.MinValue, DateOnlyFormat); - private static void RunInFastParsingLogicContext(Action testMethod, DateTime dt, String format) + private static void RunInFastParsingLogicContext(Action testMethod, DateTime dt, string format) { - const String appContextSwitchName = "Portable.System.DateTimeOnly.UseFastParsingLogic"; + const string appContextSwitchName = "Portable.System.DateTimeOnly.UseFastParsingLogic"; AppContext.SetSwitch(appContextSwitchName, true); try @@ -53,7 +53,7 @@ private static void RunInFastParsingLogicContext(Action testMe } } - private static void TimeOnlyParseWorked(DateTime dt, String format) + private static void TimeOnlyParseWorked(DateTime dt, string format) { var formatted = dt.ToString(format); Assert.Equal(TimeOnly.FromDateTime(dt), TimeOnly.Parse(formatted)); @@ -62,10 +62,10 @@ private static void TimeOnlyParseWorked(DateTime dt, String format) Assert.True(TimeOnly.TryParse(formatted.AsSpan(), out _)); } - private static void DateOnlyParseWorked(DateTime dt, String format) => + private static void DateOnlyParseWorked(DateTime dt, string format) => DateOnlyParseWorked(dt, format, dt); - private static void DateOnlyParseWorked(DateTime dt, String format, DateTime @default) + private static void DateOnlyParseWorked(DateTime dt, string format, DateTime @default) { var formatted = dt.ToString(format); Assert.Equal(DateOnly.FromDateTime(@default), DateOnly.Parse(formatted)); @@ -74,7 +74,7 @@ private static void DateOnlyParseWorked(DateTime dt, String format, DateTime @de Assert.True(DateOnly.TryParse(formatted.AsSpan(), out _)); } - private static void TimeOnlyParseFailed(DateTime dt, String format) + private static void TimeOnlyParseFailed(DateTime dt, string format) { var formatted = dt.ToString(format); Assert.Throws(() => TimeOnly.Parse(formatted)); @@ -83,7 +83,7 @@ private static void TimeOnlyParseFailed(DateTime dt, String format) Assert.False(TimeOnly.TryParse(formatted.AsSpan(), out _)); } - private static void DateOnlyParseFailed(DateTime dt, String format) + private static void DateOnlyParseFailed(DateTime dt, string format) { var formatted = dt.ToString(format); Assert.Throws(() => DateOnly.Parse(formatted)); diff --git a/DateTimeOnly.Tests/Helpers/ConditionalFact.cs b/DateTimeOnly.Tests/Helpers/ConditionalFact.cs index 2371e7a..84bea6f 100644 --- a/DateTimeOnly.Tests/Helpers/ConditionalFact.cs +++ b/DateTimeOnly.Tests/Helpers/ConditionalFact.cs @@ -8,10 +8,11 @@ namespace System.Tests public sealed class ConditionalFactAttribute : FactAttribute { public ConditionalFactAttribute( - String conditionalMemberName) => + string conditionalMemberName) => ConditionalMemberName = conditionalMemberName; // ReSharper disable once MemberCanBePrivate.Global - public String ConditionalMemberName { get; } + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public string ConditionalMemberName { get; } } } diff --git a/DateTimeOnly.Tests/Helpers/ConditionalFactDiscoverer.cs b/DateTimeOnly.Tests/Helpers/ConditionalFactDiscoverer.cs index e30991c..112da7d 100644 --- a/DateTimeOnly.Tests/Helpers/ConditionalFactDiscoverer.cs +++ b/DateTimeOnly.Tests/Helpers/ConditionalFactDiscoverer.cs @@ -21,17 +21,17 @@ public override IEnumerable Discover( { IEnumerable testCases = base.Discover(discoveryOptions, testMethod, factAttribute); - if (factAttribute.GetConstructorArguments().SingleOrDefault() is String conditionMemberName) + if (factAttribute.GetConstructorArguments().SingleOrDefault() is not string conditionMemberName) { - var typeInfo = testMethod.Method?.ToRuntimeMethod().DeclaringType?.GetTypeInfo(); - var methodInfo = typeInfo?.GetDeclaredProperty(conditionMemberName)?.GetMethod; - if (methodInfo?.Invoke(null, null) is false) - { - return testCases.Select(_ => new SkippedTestCase(_, conditionMemberName)); - } + return testCases; } - return testCases; + var typeInfo = testMethod.Method?.ToRuntimeMethod().DeclaringType?.GetTypeInfo(); + var methodInfo = typeInfo?.GetDeclaredProperty(conditionMemberName)?.GetMethod; + + return methodInfo?.Invoke(null, null) is false + ? testCases.Select(_ => new SkippedTestCase(_, conditionMemberName)) + : testCases; } } } \ No newline at end of file diff --git a/DateTimeOnly.Tests/Helpers/DateTime.cs b/DateTimeOnly.Tests/Helpers/DateTime.cs index 79f2c86..de193bc 100644 --- a/DateTimeOnly.Tests/Helpers/DateTime.cs +++ b/DateTimeOnly.Tests/Helpers/DateTime.cs @@ -3,18 +3,18 @@ namespace System.Tests { internal static class DateTimeExtensions { - internal static System.DateTime Create(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) => - new System.DateTime(year, month, day, hour, minute, second, millisecond) + internal static DateTime Create(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) => + new DateTime(year, month, day, hour, minute, second, millisecond) .Add(new TimeSpan(microsecond * Diagnostics.TimeSpan.TicksPerMicrosecond)); /// /// The microseconds component, expressed as a value between 0 and 999. /// - internal static int Microsecond(this System.DateTime dateTime) => (int)((dateTime.Ticks / Diagnostics.TimeSpan.TicksPerMicrosecond) % 1000); + internal static int Microsecond(this DateTime dateTime) => (int)(dateTime.Ticks / Diagnostics.TimeSpan.TicksPerMicrosecond % 1000); /// /// The nanoseconds component, expressed as a value between 0 and 900 (in increments of 100 nanoseconds). /// - internal static int Nanosecond(this System.DateTime dateTime) => (int)(dateTime.Ticks % Diagnostics.TimeSpan.TicksPerMicrosecond) * 100; + internal static int Nanosecond(this DateTime dateTime) => (int)(dateTime.Ticks % Diagnostics.TimeSpan.TicksPerMicrosecond) * 100; } } diff --git a/DateTimeOnly.Tests/Helpers/SkippedTestCase.cs b/DateTimeOnly.Tests/Helpers/SkippedTestCase.cs index 9cf7a9b..badb94b 100644 --- a/DateTimeOnly.Tests/Helpers/SkippedTestCase.cs +++ b/DateTimeOnly.Tests/Helpers/SkippedTestCase.cs @@ -11,30 +11,29 @@ internal sealed class SkippedTestCase : LongLivedMarshalByRefObject, IXunitTestC { private readonly IXunitTestCase _testCase; - private readonly String _skippedReason; - + // ReSharper disable once UnusedMember.Global public SkippedTestCase() { - _skippedReason = String.Empty; + SkipReason = string.Empty; _testCase = this; } internal SkippedTestCase( - IXunitTestCase testCase, String skippedReason) + IXunitTestCase testCase, string skippedReason) { - _skippedReason = skippedReason; + SkipReason = skippedReason; _testCase = testCase; } - public Int32 Timeout => _testCase.Timeout; + public string SkipReason { get; } - public String SkipReason => _skippedReason; + public int Timeout => _testCase.Timeout; - public String UniqueID => _testCase.UniqueID; + public string UniqueID => _testCase.UniqueID; public IMethodInfo Method => _testCase.Method; - public String DisplayName => _testCase.DisplayName; + public string DisplayName => _testCase.DisplayName; public Exception InitializationException => _testCase.InitializationException; @@ -46,20 +45,20 @@ public ISourceInformation SourceInformation public ITestMethod TestMethod => _testCase.TestMethod; - public Dictionary> Traits => _testCase.Traits; + public Dictionary> Traits => _testCase.Traits; - public Object[] TestMethodArguments => _testCase.TestMethodArguments; + public object[] TestMethodArguments => _testCase.TestMethodArguments; public void Deserialize(IXunitSerializationInfo info) => _testCase.Deserialize(info); public Task RunAsync( IMessageSink diagnosticMessageSink, IMessageBus messageBus, - Object[] constructorArguments, + object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) => new XunitTestCaseRunner( - this, DisplayName, _skippedReason, constructorArguments, + this, DisplayName, SkipReason, constructorArguments, TestMethodArguments, messageBus, aggregator, cancellationTokenSource).RunAsync(); public void Serialize(IXunitSerializationInfo info) => _testCase.Serialize(info); diff --git a/DateTimeOnly.Tests/TimeOnlyTests.cs b/DateTimeOnly.Tests/TimeOnlyTests.cs index 2a39889..e1d8306 100644 --- a/DateTimeOnly.Tests/TimeOnlyTests.cs +++ b/DateTimeOnly.Tests/TimeOnlyTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// ReSharper disable All + using System.Collections.Generic; using System.Globalization; using System.Runtime.CompilerServices; diff --git a/DateTimeOnly.sln.DotSettings b/DateTimeOnly.sln.DotSettings index 7d26482..8204ac8 100644 --- a/DateTimeOnly.sln.DotSettings +++ b/DateTimeOnly.sln.DotSettings @@ -1,4 +1,7 @@  + UseKeyword + UseKeyword True True + True True \ No newline at end of file diff --git a/DateTimeOnly/DateOnly.cs b/DateTimeOnly/DateOnly.cs index 7548423..8fd83c0 100644 --- a/DateTimeOnly/DateOnly.cs +++ b/DateTimeOnly/DateOnly.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// ReSharper disable All + using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -421,7 +423,7 @@ private static ParseFailureKind TryParseInternal(ReadOnlySpan s, IFormatPr } DateTimeResult dtResult = default; - dtResult.Init(s); + DateTimeResult.Init(s); if (!DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult)) { @@ -488,7 +490,7 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, Read } DateTimeResult dtResult = default; - dtResult.Init(s); + DateTimeResult.Init(s); if (!DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult)) { @@ -569,7 +571,7 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, stri // Create a new result each time to ensure the runs are independent. Carry through // flags from the caller and return the result. DateTimeResult dtResult = default; - dtResult.Init(s); + DateTimeResult.Init(s); if (DateTimeParse.TryParseExact(s, format.AsSpan(), dtfiToUse, style, ref dtResult) && ((dtResult.flags & ParseFlagsDateMask) == 0)) { result = new DateOnly(DayNumberFromDateTime(dtResult.parsedDate)); diff --git a/DateTimeOnly/Helpers/DateTime.cs b/DateTimeOnly/Helpers/DateTime.cs index ab9c6cf..52fc4bc 100644 --- a/DateTimeOnly/Helpers/DateTime.cs +++ b/DateTimeOnly/Helpers/DateTime.cs @@ -1,86 +1,85 @@ using System.Runtime.CompilerServices; // ReSharper disable once CheckNamespace -namespace System.Diagnostics +namespace System.Diagnostics; + +internal static class DateTime { - internal static class DateTime + // Number of 100ns ticks per time unit + private const int MicrosecondsPerMillisecond = 1000; + private const long TicksPerMicrosecond = 10; + private const long TicksPerMillisecond = TicksPerMicrosecond * MicrosecondsPerMillisecond; + private const long TicksPerSecond = TicksPerMillisecond * 1000; + private const long TicksPerMinute = TicksPerSecond * 60; + private const long TicksPerHour = TicksPerMinute * 60; + private const long TicksPerDay = TicksPerHour * 24; + + // Number of milliseconds per time unit + private const int MillisPerSecond = 1000; + + // Number of days in a non-leap year + private const int DaysPerYear = 365; + // Number of days in 4 years + private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461 + // Number of days in 100 years + private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524 + // Number of days in 400 years + private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 + + // Number of days from 1/1/0001 to 12/31/9999 + private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059 + + private const long MaxTicks = DaysTo10000 * TicksPerDay - 1; + + internal static ulong TimeToTicks(int hour, int minute, int second, int millisecond) { - // Number of 100ns ticks per time unit - private const int MicrosecondsPerMillisecond = 1000; - private const long TicksPerMicrosecond = 10; - private const long TicksPerMillisecond = TicksPerMicrosecond * MicrosecondsPerMillisecond; - private const long TicksPerSecond = TicksPerMillisecond * 1000; - private const long TicksPerMinute = TicksPerSecond * 60; - private const long TicksPerHour = TicksPerMinute * 60; - private const long TicksPerDay = TicksPerHour * 24; - - // Number of milliseconds per time unit - private const int MillisPerSecond = 1000; - - // Number of days in a non-leap year - private const int DaysPerYear = 365; - // Number of days in 4 years - private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461 - // Number of days in 100 years - private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524 - // Number of days in 400 years - private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 - - // Number of days from 1/1/0001 to 12/31/9999 - private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059 - - private const long MaxTicks = DaysTo10000 * TicksPerDay - 1; - - internal static ulong TimeToTicks(int hour, int minute, int second, int millisecond) - { - ulong ticks = TimeToTicks(hour, minute, second); + var ticks = TimeToTicks(hour, minute, second); - if ((uint)millisecond >= MillisPerSecond) - { - throw new ArgumentOutOfRangeException(nameof(millisecond), - SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1)); - } + if ((uint)millisecond >= MillisPerSecond) + { + throw new ArgumentOutOfRangeException(nameof(millisecond), + SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1)); + } - ticks += (uint)millisecond * (uint)TicksPerMillisecond; + ticks += (uint)millisecond * (uint)TicksPerMillisecond; - Debug.Assert(ticks <= MaxTicks, "Input parameters validated already"); + Debug.Assert(ticks <= MaxTicks, "Input parameters validated already"); - return ticks; - } + return ticks; + } - internal static ulong TimeToTicks(int hour, int minute, int second, int millisecond, int microsecond) - { - ulong ticks = TimeToTicks(hour, minute, second, millisecond); + internal static ulong TimeToTicks(int hour, int minute, int second, int millisecond, int microsecond) + { + var ticks = TimeToTicks(hour, minute, second, millisecond); - if ((uint)microsecond >= MicrosecondsPerMillisecond) - { - throw new ArgumentOutOfRangeException(nameof(microsecond), - SR.Format(SR.ArgumentOutOfRange_Range, 0, MicrosecondsPerMillisecond - 1)); - } + if ((uint)microsecond >= MicrosecondsPerMillisecond) + { + throw new ArgumentOutOfRangeException(nameof(microsecond), + SR.Format(SR.ArgumentOutOfRange_Range, 0, MicrosecondsPerMillisecond - 1)); + } - ticks += (uint)microsecond * (uint)TicksPerMicrosecond; + ticks += (uint)microsecond * (uint)TicksPerMicrosecond; - Debug.Assert(ticks <= MaxTicks, "Input parameters validated already"); + Debug.Assert(ticks <= MaxTicks, "Input parameters validated already"); - return ticks; - } + return ticks; + } - // Return the tick count corresponding to the given hour, minute, second. - // Will check the if the parameters are valid. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong TimeToTicks(int hour, int minute, int second) + // Return the tick count corresponding to the given hour, minute, second. + // Will check the if the parameters are valid. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong TimeToTicks(int hour, int minute, int second) + { + if ((uint)hour >= 24 || (uint)minute >= 60 || (uint)second >= 60) { - if ((uint)hour >= 24 || (uint)minute >= 60 || (uint)second >= 60) - { - ThrowHelper.ThrowArgumentOutOfRange_BadHourMinuteSecond(); - } - - int totalSeconds = hour * 3600 + minute * 60 + second; - return (uint)totalSeconds * (ulong)TicksPerSecond; + ThrowHelper.ThrowArgumentOutOfRange_BadHourMinuteSecond(); } - internal static int Microseconds(this TimeSpan timeSpan) => (int)((timeSpan.Ticks / TicksPerMicrosecond) % 1000); - - internal static int Nanoseconds(this TimeSpan timeSpan) => (int)((timeSpan.Ticks % TicksPerMicrosecond) * 100); + var totalSeconds = hour * 3600 + minute * 60 + second; + return (uint)totalSeconds * (ulong)TicksPerSecond; } + + internal static int Microseconds(this TimeSpan timeSpan) => (int)(timeSpan.Ticks / TicksPerMicrosecond % 1000); + + internal static int Nanoseconds(this TimeSpan timeSpan) => (int)(timeSpan.Ticks % TicksPerMicrosecond * 100); } diff --git a/DateTimeOnly/Helpers/DateTimeFormat.cs b/DateTimeOnly/Helpers/DateTimeFormat.cs index e8554e5..4e1ee64 100644 --- a/DateTimeOnly/Helpers/DateTimeFormat.cs +++ b/DateTimeOnly/Helpers/DateTimeFormat.cs @@ -5,317 +5,316 @@ using System.Globalization; using System.Runtime.CompilerServices; -namespace System +namespace System; + +internal static class DateTimeFormat { - internal static class DateTimeFormat - { - private static readonly DateTimeFormatInfo InvariantFormatInfo = CultureInfo.InvariantCulture.DateTimeFormat; + private static readonly DateTimeFormatInfo InvariantFormatInfo = CultureInfo.InvariantCulture.DateTimeFormat; - private static readonly string[] InvariantAbbreviatedMonthNames = InvariantFormatInfo.AbbreviatedMonthNames; + private static readonly string[] InvariantAbbreviatedMonthNames = InvariantFormatInfo.AbbreviatedMonthNames; - private static readonly string[] InvariantAbbreviatedDayNames = InvariantFormatInfo.AbbreviatedDayNames; + private static readonly string[] InvariantAbbreviatedDayNames = InvariantFormatInfo.AbbreviatedDayNames; - internal static string Format(DateTime dateTime, string format, IFormatProvider? provider) => - dateTime.ToString(format, provider); + internal static string Format(DateTime dateTime, string format, IFormatProvider? provider) => + dateTime.ToString(format, provider); - internal static bool TryFormat(DateTime dateTime, Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { + internal static bool TryFormat(DateTime dateTime, Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { #if NETSTANDARD2_0 || NETFRAMEWORK - var value = dateTime.ToString(format.ToString(), provider); - charsWritten = value.Length; + var value = dateTime.ToString(format.ToString(), provider); + charsWritten = value.Length; #pragma warning disable PC001 // API not supported on all platforms - return value.AsSpan().TryCopyTo(destination); + return value.AsSpan().TryCopyTo(destination); #pragma warning restore PC001 // API not supported on all platforms #else - return dateTime.TryFormat(destination, out charsWritten, format, provider); + return dateTime.TryFormat(destination, out charsWritten, format, provider); #endif - } + } - // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global - internal static bool IsValidCustomDateFormat(ReadOnlySpan format, bool throwOnError) - { - int i = 0; + // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global + internal static bool IsValidCustomDateFormat(ReadOnlySpan format, bool throwOnError) + { + var i = 0; - while (i < format.Length) + while (i < format.Length) + { + switch (format[i]) { - switch (format[i]) - { - case '\\': - if (i == format.Length - 1) - { - if (throwOnError) - { - throw new FormatException(SR.Format_InvalidString); - } - - return false; - } - - i += 2; - break; - - case '\'': - case '"': - char quoteChar = format[i++]; - while (i < format.Length && format[i] != quoteChar) + case '\\': + if (i == format.Length - 1) + { + if (throwOnError) { - i++; + throw new FormatException(SR.Format_InvalidString); } - if (i >= format.Length) - { - if (throwOnError) - { - throw new FormatException(SR.Format(SR.Format_BadQuote, quoteChar)); - } + return false; + } - return false; - } + i += 2; + break; + case '\'': + case '"': + var quoteChar = format[i++]; + while (i < format.Length && format[i] != quoteChar) + { i++; - break; - - case ':': - case 't': - case 'f': - case 'F': - case 'h': - case 'H': - case 'm': - case 's': - case 'z': - case 'K': - // reject non-date formats + } + + if (i >= format.Length) + { if (throwOnError) { - throw new FormatException(SR.Format_InvalidString); + throw new FormatException(SR.Format(SR.Format_BadQuote, quoteChar)); } return false; - - default: - i++; - break; - } + } + + i++; + break; + + case ':': + case 't': + case 'f': + case 'F': + case 'h': + case 'H': + case 'm': + case 's': + case 'z': + case 'K': + // reject non-date formats + if (throwOnError) + { + throw new FormatException(SR.Format_InvalidString); + } + + return false; + + default: + i++; + break; } - - return true; } - // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global - internal static bool IsValidCustomTimeFormat(ReadOnlySpan format, bool throwOnError) - { - int length = format.Length; - int i = 0; - - while (i < length) - { - switch (format[i]) - { - case '\\': - if (i == length - 1) - { - if (throwOnError) - { - throw new FormatException(SR.Format_InvalidString); - } - - return false; - } + return true; + } - i += 2; - break; + // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global + internal static bool IsValidCustomTimeFormat(ReadOnlySpan format, bool throwOnError) + { + var length = format.Length; + var i = 0; - case '\'': - case '"': - char quoteChar = format[i++]; - while (i < length && format[i] != quoteChar) + while (i < length) + { + switch (format[i]) + { + case '\\': + if (i == length - 1) + { + if (throwOnError) { - i++; + throw new FormatException(SR.Format_InvalidString); } - if (i >= length) - { - if (throwOnError) - { - throw new FormatException(SR.Format(SR.Format_BadQuote, quoteChar)); - } + return false; + } - return false; - } + i += 2; + break; + case '\'': + case '"': + var quoteChar = format[i++]; + while (i < length && format[i] != quoteChar) + { i++; - break; - - case 'd': - case 'M': - case 'y': - case '/': - case 'z': - case 'k': + } + + if (i >= length) + { if (throwOnError) { - throw new FormatException(SR.Format_InvalidString); + throw new FormatException(SR.Format(SR.Format_BadQuote, quoteChar)); } return false; - - default: - i++; - break; - } + } + + i++; + break; + + case 'd': + case 'M': + case 'y': + case '/': + case 'z': + case 'k': + if (throwOnError) + { + throw new FormatException(SR.Format_InvalidString); + } + + return false; + + default: + i++; + break; } - - return true; } - // 012345678901234567890123456789012 - // --------------------------------- - // 05:30:45.7680000 - internal static bool TryFormatTimeOnlyO(int hour, int minute, int second, long fraction, Span destination) + return true; + } + + // 012345678901234567890123456789012 + // --------------------------------- + // 05:30:45.7680000 + internal static bool TryFormatTimeOnlyO(int hour, int minute, int second, long fraction, Span destination) + { + if (destination.Length < 16) { - if (destination.Length < 16) - { - return false; - } + return false; + } - WriteTwoDecimalDigits((uint)hour, destination, 0); - destination[2] = ':'; - WriteTwoDecimalDigits((uint)minute, destination, 3); - destination[5] = ':'; - WriteTwoDecimalDigits((uint)second, destination, 6); - destination[8] = '.'; + WriteTwoDecimalDigits((uint)hour, destination, 0); + destination[2] = ':'; + WriteTwoDecimalDigits((uint)minute, destination, 3); + destination[5] = ':'; + WriteTwoDecimalDigits((uint)second, destination, 6); + destination[8] = '.'; #pragma warning disable PC001 // API not supported on all platforms - WriteDigits((uint)fraction, destination.Slice(9, 7)); + WriteDigits((uint)fraction, destination.Slice(9, 7)); #pragma warning restore PC001 // API not supported on all platforms - return true; - } + return true; + } - // 012345678901234567890123456789012 - // --------------------------------- - // 05:30:45 - internal static bool TryFormatTimeOnlyR(int hour, int minute, int second, Span destination) + // 012345678901234567890123456789012 + // --------------------------------- + // 05:30:45 + internal static bool TryFormatTimeOnlyR(int hour, int minute, int second, Span destination) + { + if (destination.Length < 8) { - if (destination.Length < 8) - { - return false; - } + return false; + } - WriteTwoDecimalDigits((uint)hour, destination, 0); - destination[2] = ':'; - WriteTwoDecimalDigits((uint)minute, destination, 3); - destination[5] = ':'; - WriteTwoDecimalDigits((uint)second, destination, 6); + WriteTwoDecimalDigits((uint)hour, destination, 0); + destination[2] = ':'; + WriteTwoDecimalDigits((uint)minute, destination, 3); + destination[5] = ':'; + WriteTwoDecimalDigits((uint)second, destination, 6); - return true; - } + return true; + } - // Roundtrippable format. One of - // 012345678901234567890123456789012 - // --------------------------------- - // 2017-06-12 - internal static bool TryFormatDateOnlyO(int year, int month, int day, Span destination) + // Roundtrippable format. One of + // 012345678901234567890123456789012 + // --------------------------------- + // 2017-06-12 + internal static bool TryFormatDateOnlyO(int year, int month, int day, Span destination) + { + if (destination.Length < 10) { - if (destination.Length < 10) - { - return false; - } - - WriteFourDecimalDigits((uint)year, destination, 0); - destination[4] = '-'; - WriteTwoDecimalDigits((uint)month, destination, 5); - destination[7] = '-'; - WriteTwoDecimalDigits((uint)day, destination, 8); - return true; + return false; } - // Rfc1123 - // 01234567890123456789012345678 - // ----------------------------- - // Tue, 03 Jan 2017 - internal static bool TryFormatDateOnlyR(DayOfWeek dayOfWeek, int year, int month, int day, Span destination) - { - if (destination.Length < 16) - { - return false; - } + WriteFourDecimalDigits((uint)year, destination, 0); + destination[4] = '-'; + WriteTwoDecimalDigits((uint)month, destination, 5); + destination[7] = '-'; + WriteTwoDecimalDigits((uint)day, destination, 8); + return true; + } - string dayAbbrev = InvariantAbbreviatedDayNames[(int)dayOfWeek]; - Debug.Assert(dayAbbrev.Length == 3); - - string monthAbbrev = InvariantAbbreviatedMonthNames[month - 1]; - Debug.Assert(monthAbbrev.Length == 3); - - destination[0] = dayAbbrev[0]; - destination[1] = dayAbbrev[1]; - destination[2] = dayAbbrev[2]; - destination[3] = ','; - destination[4] = ' '; - WriteTwoDecimalDigits((uint)day, destination, 5); - destination[7] = ' '; - destination[8] = monthAbbrev[0]; - destination[9] = monthAbbrev[1]; - destination[10] = monthAbbrev[2]; - destination[11] = ' '; - WriteFourDecimalDigits((uint)year, destination, 12); - return true; + // Rfc1123 + // 01234567890123456789012345678 + // ----------------------------- + // Tue, 03 Jan 2017 + internal static bool TryFormatDateOnlyR(DayOfWeek dayOfWeek, int year, int month, int day, Span destination) + { + if (destination.Length < 16) + { + return false; } - /// - /// Writes a value [ 00 .. 99 ] to the buffer starting at the specified offset. - /// This method performs best when the starting index is a constant literal. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteTwoDecimalDigits(uint value, Span destination, int offset) - { - Debug.Assert(value <= 99); + var dayAbbrev = InvariantAbbreviatedDayNames[(int)dayOfWeek]; + Debug.Assert(dayAbbrev.Length == 3); + + var monthAbbrev = InvariantAbbreviatedMonthNames[month - 1]; + Debug.Assert(monthAbbrev.Length == 3); + + destination[0] = dayAbbrev[0]; + destination[1] = dayAbbrev[1]; + destination[2] = dayAbbrev[2]; + destination[3] = ','; + destination[4] = ' '; + WriteTwoDecimalDigits((uint)day, destination, 5); + destination[7] = ' '; + destination[8] = monthAbbrev[0]; + destination[9] = monthAbbrev[1]; + destination[10] = monthAbbrev[2]; + destination[11] = ' '; + WriteFourDecimalDigits((uint)year, destination, 12); + return true; + } - uint temp = '0' + value; - value /= 10; - destination[offset + 1] = (char)(temp - (value * 10)); - destination[offset] = (char)('0' + value); - } + /// + /// Writes a value [ 00 .. 99 ] to the buffer starting at the specified offset. + /// This method performs best when the starting index is a constant literal. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteTwoDecimalDigits(uint value, Span destination, int offset) + { + Debug.Assert(value <= 99); - /// - /// Writes a value [ 0000 .. 9999 ] to the buffer starting at the specified offset. - /// This method performs best when the starting index is a constant literal. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteFourDecimalDigits(uint value, Span buffer, int startingIndex) - { - Debug.Assert(value <= 9999); + var temp = '0' + value; + value /= 10; + destination[offset + 1] = (char)(temp - value * 10); + destination[offset] = (char)('0' + value); + } - uint temp = '0' + value; - value /= 10; - buffer[startingIndex + 3] = (char)(temp - (value * 10)); + /// + /// Writes a value [ 0000 .. 9999 ] to the buffer starting at the specified offset. + /// This method performs best when the starting index is a constant literal. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteFourDecimalDigits(uint value, Span buffer, int startingIndex) + { + Debug.Assert(value <= 9999); - temp = '0' + value; - value /= 10; - buffer[startingIndex + 2] = (char)(temp - (value * 10)); + var temp = '0' + value; + value /= 10; + buffer[startingIndex + 3] = (char)(temp - value * 10); - temp = '0' + value; - value /= 10; - buffer[startingIndex + 1] = (char)(temp - (value * 10)); + temp = '0' + value; + value /= 10; + buffer[startingIndex + 2] = (char)(temp - value * 10); - buffer[startingIndex] = (char)('0' + value); - } + temp = '0' + value; + value /= 10; + buffer[startingIndex + 1] = (char)(temp - value * 10); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteDigits(ulong value, Span buffer) - { - // We can mutate the 'value' parameter since it's a copy-by-value local. - // It'll be used to represent the value left over after each division by 10. + buffer[startingIndex] = (char)('0' + value); + } - for (int i = buffer.Length - 1; i >= 1; i--) - { - ulong temp = '0' + value; - value /= 10; - buffer[i] = (char)(temp - (value * 10)); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteDigits(ulong value, Span buffer) + { + // We can mutate the 'value' parameter since it's a copy-by-value local. + // It'll be used to represent the value left over after each division by 10. - Debug.Assert(value < 10); - buffer[0] = (char)('0' + value); + for (var i = buffer.Length - 1; i >= 1; i--) + { + var temp = '0' + value; + value /= 10; + buffer[i] = (char)(temp - value * 10); } + + Debug.Assert(value < 10); + buffer[0] = (char)('0' + value); } } diff --git a/DateTimeOnly/Helpers/DateTimeParse.cs b/DateTimeOnly/Helpers/DateTimeParse.cs index 445a11a..d41cca5 100644 --- a/DateTimeOnly/Helpers/DateTimeParse.cs +++ b/DateTimeOnly/Helpers/DateTimeParse.cs @@ -5,97 +5,97 @@ using System.Globalization; using System.Linq; -namespace System +namespace System; + +internal static class DateTimeParse { - internal static class DateTimeParse - { - private const String AppContextSwitchName = "Portable.System.DateTimeOnly.UseFastParsingLogic"; + private const string AppContextSwitchName = "Portable.System.DateTimeOnly.UseFastParsingLogic"; - private static readonly Char[] ValidDateOnlyFormatSpecifiers = { 'd', 'D', 'm', 'M', 'y', 'Y' }; + private static readonly char[] ValidDateOnlyFormatSpecifiers = { 'd', 'D', 'm', 'M', 'y', 'Y' }; - private static readonly Char[] ValidTimeOnlyFormatSpecifiers = { 't', 'T' }; + private static readonly char[] ValidTimeOnlyFormatSpecifiers = { 't', 'T' }; + + internal static bool TryParseExact(ReadOnlySpan s, ReadOnlySpan format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result) + { + var success = DateTime.TryParseExact(s.ToString(), format.ToString(), dtfi, style, out var dt); + result.parsedDate = dt; + return success; + } + + internal static bool TryParse(ReadOnlySpan s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result) + { + var success = DateTime.TryParse( + s.ToString(), dtfi, styles | DateTimeStyles.NoCurrentDateDefault, + out var dt); + result.parsedDate = dt; - internal static bool TryParseExact(ReadOnlySpan s, ReadOnlySpan format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result) + if (!success || IsFastParsingLogicEnabled()) { - var success = DateTime.TryParseExact(s.ToString(), format.ToString(), dtfi, style, out var dt); - result.parsedDate = dt; return success; } - internal static bool TryParse(ReadOnlySpan s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result) + if (dt.Date != DateTime.MinValue || + DateTime.TryParseExact(s.ToString(), GetValidDateOnlyFormatStrings(dtfi), dtfi, styles, out _)) { - var success = DateTime.TryParse( - s.ToString(), dtfi, styles | DateTimeStyles.NoCurrentDateDefault, - out var dt); - result.parsedDate = dt; - - if (!success || IsFastParsingLogicEnabled()) - { - return success; - } - - if (dt.Date != DateTime.MinValue || - DateTime.TryParseExact(s.ToString(), GetValidDateOnlyFormatStrings(dtfi), dtfi, styles, out _)) - { - result.flags |= ParseFlags.HaveDate; - } - - if (dt.TimeOfDay != TimeSpan.Zero || - DateTime.TryParseExact(s.ToString(), GetValidTimeOnlyFormatStrings(dtfi), dtfi, styles, out _)) - { - result.flags |= ParseFlags.HaveTime; - } + result.flags |= ParseFlags.HaveDate; + } - return success; + if (dt.TimeOfDay != TimeSpan.Zero || + DateTime.TryParseExact(s.ToString(), GetValidTimeOnlyFormatStrings(dtfi), dtfi, styles, out _)) + { + result.flags |= ParseFlags.HaveTime; } - private static Boolean IsFastParsingLogicEnabled() => - AppContext.TryGetSwitch(AppContextSwitchName, out var isEnabled) && isEnabled; + return success; + } - private static String[] GetValidDateOnlyFormatStrings(DateTimeFormatInfo dtfi) => - ValidDateOnlyFormatSpecifiers.SelectMany(dtfi.GetAllDateTimePatterns).ToArray(); + private static bool IsFastParsingLogicEnabled() => + AppContext.TryGetSwitch(AppContextSwitchName, out var isEnabled) && isEnabled; - private static String[] GetValidTimeOnlyFormatStrings(DateTimeFormatInfo dtfi) => - ValidTimeOnlyFormatSpecifiers.SelectMany(dtfi.GetAllDateTimePatterns).ToArray(); - } + private static string[] GetValidDateOnlyFormatStrings(DateTimeFormatInfo dtfi) => + ValidDateOnlyFormatSpecifiers.SelectMany(dtfi.GetAllDateTimePatterns).ToArray(); + private static string[] GetValidTimeOnlyFormatStrings(DateTimeFormatInfo dtfi) => + ValidTimeOnlyFormatSpecifiers.SelectMany(dtfi.GetAllDateTimePatterns).ToArray(); +} - internal enum ParseFailureKind - { - None = 0, - FormatWithParameter = 3, - FormatWithOriginalDateTime = 4, - FormatWithFormatSpecifier = 5, - WrongParts = 8, // DateOnly and TimeOnly specific value. Unrelated date parts when parsing DateOnly or Unrelated time parts when parsing TimeOnly - } - [Flags] - internal enum ParseFlags - { - HaveYear = 0x00000001, - HaveMonth = 0x00000002, - HaveDay = 0x00000004, - HaveHour = 0x00000008, - HaveMinute = 0x00000010, - HaveSecond = 0x00000020, - HaveTime = 0x00000040, - HaveDate = 0x00000080, - TimeZoneUsed = 0x00000100, - TimeZoneUtc = 0x00000200, - ParsedMonthName = 0x00000400, - CaptureOffset = 0x00000800, - UtcSortPattern = 0x00004000, - } +internal enum ParseFailureKind +{ + None = 0, + FormatWithParameter = 3, + FormatWithOriginalDateTime = 4, + FormatWithFormatSpecifier = 5, + WrongParts = 8 // DateOnly and TimeOnly specific value. Unrelated date parts when parsing DateOnly or Unrelated time parts when parsing TimeOnly +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - internal ref struct DateTimeResult - { +[Flags] +internal enum ParseFlags +{ + HaveYear = 0x00000001, + HaveMonth = 0x00000002, + HaveDay = 0x00000004, + HaveHour = 0x00000008, + HaveMinute = 0x00000010, + HaveSecond = 0x00000020, + HaveTime = 0x00000040, + HaveDate = 0x00000080, + TimeZoneUsed = 0x00000100, + TimeZoneUtc = 0x00000200, + ParsedMonthName = 0x00000400, + CaptureOffset = 0x00000800, + UtcSortPattern = 0x00004000 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +internal ref struct DateTimeResult +{ #pragma warning disable 649 - internal ParseFlags flags; + internal ParseFlags flags; #pragma warning restore 649 - internal DateTime parsedDate; + internal DateTime parsedDate; - internal void Init(ReadOnlySpan _) { } - } + // ReSharper disable once UnusedParameter.Global + internal static void Init(ReadOnlySpan _) { } } diff --git a/DateTimeOnly/Helpers/ExceptionArgument.cs b/DateTimeOnly/Helpers/ExceptionArgument.cs index e5a00ff..670ab24 100644 --- a/DateTimeOnly/Helpers/ExceptionArgument.cs +++ b/DateTimeOnly/Helpers/ExceptionArgument.cs @@ -1,11 +1,10 @@ using System.Diagnostics.CodeAnalysis; -namespace System +namespace System; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +internal enum ExceptionArgument { - [SuppressMessage("ReSharper", "InconsistentNaming")] - internal enum ExceptionArgument - { - s, - format - } + s, + format } diff --git a/DateTimeOnly/Helpers/IParsable.cs b/DateTimeOnly/Helpers/IParsable.cs index 922b0b3..c456cf0 100644 --- a/DateTimeOnly/Helpers/IParsable.cs +++ b/DateTimeOnly/Helpers/IParsable.cs @@ -3,27 +3,14 @@ using System.Diagnostics.CodeAnalysis; -namespace System +namespace System; + +internal interface IParsable + where TSelf : IParsable? { - /// Defines a mechanism for parsing a string to a value. - /// The type that implements this interface. - internal interface IParsable - where TSelf : IParsable? - { - /// Parses a string into a value. - /// The string to parse. - /// An object that provides culture-specific formatting information about . - /// The result of parsing . - /// is null. - /// is not in the correct format. - /// is not representable by . - TSelf Parse(string s, IFormatProvider? provider); + // ReSharper disable once UnusedMember.Global + TSelf Parse(string s, IFormatProvider? provider); - /// Tries to parse a string into a value. - /// The string to parse. - /// An object that provides culture-specific formatting information about . - /// On return, contains the result of successfully parsing or an undefined value on failure. - /// true if was successfully parsed; otherwise, false. - bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(returnValue: false)] out TSelf result); - } + // ReSharper disable once UnusedMember.Global + bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(returnValue: false)] out TSelf result); } diff --git a/DateTimeOnly/Helpers/ISpanParsable.cs b/DateTimeOnly/Helpers/ISpanParsable.cs index 1dd9040..7dcb07b 100644 --- a/DateTimeOnly/Helpers/ISpanParsable.cs +++ b/DateTimeOnly/Helpers/ISpanParsable.cs @@ -3,26 +3,15 @@ using System.Diagnostics.CodeAnalysis; -namespace System +namespace System; + +// ReSharper disable once UnusedType.Global +internal interface ISpanParsable : IParsable + where TSelf : ISpanParsable? { - /// Defines a mechanism for parsing a span of characters to a value. - /// The type that implements this interface. - internal interface ISpanParsable : IParsable - where TSelf : ISpanParsable? - { - /// Parses a span of characters into a value. - /// The span of characters to parse. - /// An object that provides culture-specific formatting information about . - /// The result of parsing . - /// is not in the correct format. - /// is not representable by . - TSelf Parse(ReadOnlySpan s, IFormatProvider? provider); + // ReSharper disable once UnusedMember.Global + TSelf Parse(ReadOnlySpan s, IFormatProvider? provider); - /// Tries to parse a span of characters into a value. - /// The span of characters to parse. - /// An object that provides culture-specific formatting information about . - /// On return, contains the result of successfully parsing or an undefined value on failure. - /// true if was successfully parsed; otherwise, false. - bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(returnValue: false)] out TSelf result); - } + // ReSharper disable once UnusedMember.Global + bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(returnValue: false)] out TSelf result); } diff --git a/DateTimeOnly/Helpers/NullableAttributes.cs b/DateTimeOnly/Helpers/NullableAttributes.cs index 8adde0d..2c8d014 100644 --- a/DateTimeOnly/Helpers/NullableAttributes.cs +++ b/DateTimeOnly/Helpers/NullableAttributes.cs @@ -3,38 +3,41 @@ // See the LICENSE file in the project root for more information. // ReSharper disable once CheckNamespace -namespace System.Diagnostics.CodeAnalysis -{ - /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. - [AttributeUsage (AttributeTargets.Parameter, Inherited = false)] - internal sealed class MaybeNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter may be null. - /// - public MaybeNullWhenAttribute (bool returnValue) => ReturnValue = returnValue; +namespace System.Diagnostics.CodeAnalysis; - /// Gets the return value condition. - public bool ReturnValue { get; } - } +/// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. +[AttributeUsage (AttributeTargets.Parameter)] +internal sealed class MaybeNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute (bool returnValue) => ReturnValue = returnValue; - /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - internal sealed class NotNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + /// Gets the return value condition. + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public bool ReturnValue { get; } +} - /// Gets the return value condition. - public bool ReturnValue { get; } - } +/// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. +[AttributeUsage(AttributeTargets.Parameter)] +internal sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - /// Applied to a method that will never return under any circumstance. - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - internal sealed class DoesNotReturnAttribute : Attribute - { } + /// Gets the return value condition. + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public bool ReturnValue { get; } } + +/// Applied to a method that will never return under any circumstance. +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +internal sealed class DoesNotReturnAttribute : Attribute +{ } diff --git a/DateTimeOnly/Helpers/SR.cs b/DateTimeOnly/Helpers/SR.cs index 6733210..3296489 100644 --- a/DateTimeOnly/Helpers/SR.cs +++ b/DateTimeOnly/Helpers/SR.cs @@ -2,48 +2,47 @@ using System.Resources; using System.Runtime.CompilerServices; -namespace System +namespace System; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +internal static class SR { - [SuppressMessage("ReSharper", "InconsistentNaming")] - internal static class SR - { - private static readonly bool s_usingResourceKeys = - AppContext.TryGetSwitch("System.Resources.UseSystemResourceKeys", out bool usingResourceKeys) && usingResourceKeys; + private static readonly bool s_usingResourceKeys = + AppContext.TryGetSwitch("System.Resources.UseSystemResourceKeys", out var usingResourceKeys) && usingResourceKeys; - public static string Argument_BadFormatSpecifier => Strings.Argument_BadFormatSpecifier; + public static string Argument_BadFormatSpecifier => Strings.Argument_BadFormatSpecifier; - public static string Argument_InvalidDateStyles => Strings.Argument_InvalidDateStyles; + public static string Argument_InvalidDateStyles => Strings.Argument_InvalidDateStyles; - public static string ArgumentOutOfRange_Range => Strings.ArgumentOutOfRange_Range; + public static string ArgumentOutOfRange_Range => Strings.ArgumentOutOfRange_Range; - public static string ArgumentOutOfRange_AddValue => Strings.ArgumentOutOfRange_AddValue; + public static string ArgumentOutOfRange_AddValue => Strings.ArgumentOutOfRange_AddValue; - public static string ArgumentOutOfRange_BadHourMinuteSecond => Strings.ArgumentOutOfRange_BadHourMinuteSecond; + public static string ArgumentOutOfRange_BadHourMinuteSecond => Strings.ArgumentOutOfRange_BadHourMinuteSecond; - public static string ArgumentOutOfRange_DayNumber => Strings.ArgumentOutOfRange_DayNumber; + public static string ArgumentOutOfRange_DayNumber => Strings.ArgumentOutOfRange_DayNumber; - public static string ArgumentOutOfRange_TimeOnlyBadTicks => Strings.ArgumentOutOfRange_TimeOnlyBadTicks; + public static string ArgumentOutOfRange_TimeOnlyBadTicks => Strings.ArgumentOutOfRange_TimeOnlyBadTicks; - public static string Arg_MustBeDateOnly => Strings.Arg_MustBeDateOnly; + public static string Arg_MustBeDateOnly => Strings.Arg_MustBeDateOnly; - public static string Arg_MustBeTimeOnly => Strings.Arg_MustBeTimeOnly; + public static string Arg_MustBeTimeOnly => Strings.Arg_MustBeTimeOnly; - public static string Format_BadDateOnly => Strings.Format_BadDateOnly; + public static string Format_BadDateOnly => Strings.Format_BadDateOnly; - public static string Format_BadQuote => Strings.Format_BadQuote; + public static string Format_BadQuote => Strings.Format_BadQuote; - public static string Format_BadTimeOnly => Strings.Format_BadTimeOnly; + public static string Format_BadTimeOnly => Strings.Format_BadTimeOnly; - public static string Format_DateTimeOnlyContainsNoneDateParts => Strings.Format_DateTimeOnlyContainsNoneDateParts; + public static string Format_DateTimeOnlyContainsNoneDateParts => Strings.Format_DateTimeOnlyContainsNoneDateParts; - public static string Format_InvalidString => Strings.Format_InvalidString; + public static string Format_InvalidString => Strings.Format_InvalidString; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static string Format(string resourceFormat, object? p1) => - s_usingResourceKeys ? string.Join(", ", resourceFormat, p1) : string.Format(resourceFormat, p1); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static string Format(string resourceFormat, object? p1) => + s_usingResourceKeys ? string.Join(", ", resourceFormat, p1) : string.Format(resourceFormat, p1); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static string Format(string resourceFormat, object? p1, object? p2) => - s_usingResourceKeys ? string.Join(", ", resourceFormat, p1, p2) : string.Format(resourceFormat, p1, p2); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static string Format(string resourceFormat, object? p1, object? p2) => + s_usingResourceKeys ? string.Join(", ", resourceFormat, p1, p2) : string.Format(resourceFormat, p1, p2); } diff --git a/DateTimeOnly/Helpers/SpanAction.cs b/DateTimeOnly/Helpers/SpanAction.cs index 93186ad..afa5db2 100644 --- a/DateTimeOnly/Helpers/SpanAction.cs +++ b/DateTimeOnly/Helpers/SpanAction.cs @@ -1,6 +1,5 @@ // ReSharper disable once CheckNamespace -namespace System.Buffers -{ - internal delegate void SpanAction(Span span, TArg arg); -} +namespace System.Buffers; + +internal delegate void SpanAction(Span span, TArg arg); diff --git a/DateTimeOnly/Helpers/StringFactory.cs b/DateTimeOnly/Helpers/StringFactory.cs index 69d441d..1815f70 100644 --- a/DateTimeOnly/Helpers/StringFactory.cs +++ b/DateTimeOnly/Helpers/StringFactory.cs @@ -1,20 +1,20 @@ using System.Runtime.CompilerServices; // ReSharper disable once CheckNamespace -namespace System.Diagnostics +namespace System.Diagnostics; + +internal static class StringFactory { - internal static class StringFactory + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string Create(int length, TState state, Buffers.SpanAction action) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string Create(int length, TState state, Buffers.SpanAction action) - { #if NETSTANDARD2_0 || NETFRAMEWORK - var destination = new Span(new char[length]); - action(destination, state); - return destination.ToString(); + var destination = new Span(new char[length]); + action(destination, state); + return destination.ToString(); #else - return string.Create(length, state, (destination, state) => action(destination, state)); + return string.Create(length, state, + (destination, localState) => action(destination, localState)); #endif - } } } diff --git a/DateTimeOnly/Helpers/StringSyntaxAttribute.cs b/DateTimeOnly/Helpers/StringSyntaxAttribute.cs index 211ca1f..3da782d 100644 --- a/DateTimeOnly/Helpers/StringSyntaxAttribute.cs +++ b/DateTimeOnly/Helpers/StringSyntaxAttribute.cs @@ -1,35 +1,34 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if !NET7_0_OR_GREATER - // ReSharper disable once CheckNamespace -namespace System.Diagnostics.CodeAnalysis +namespace System.Diagnostics.CodeAnalysis; + +/// Specifies the syntax used in a string. +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] +internal sealed class StringSyntaxAttribute : Attribute { - /// Specifies the syntax used in a string. - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] - internal sealed class StringSyntaxAttribute : Attribute + /// Initializes the with the identifier of the syntax used. + /// The syntax identifier. + public StringSyntaxAttribute(string syntax) { - /// Initializes the with the identifier of the syntax used. - /// The syntax identifier. - public StringSyntaxAttribute(string syntax) - { - Syntax = syntax; - Arguments = Array.Empty(); - } + Syntax = syntax; + Arguments = Array.Empty(); + } - /// Gets the identifier of the syntax used. - public string Syntax { get; } + /// Gets the identifier of the syntax used. + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public string Syntax { get; } - /// Optional arguments associated with the specific syntax employed. - public object?[] Arguments { get; } + /// Optional arguments associated with the specific syntax employed. + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public object?[] Arguments { get; } - /// The syntax identifier for strings containing date format specifiers. - public const string DateOnlyFormat = nameof(DateOnlyFormat); + /// The syntax identifier for strings containing date format specifiers. + public const string DateOnlyFormat = nameof(DateOnlyFormat); - /// The syntax identifier for strings containing time format specifiers. - public const string TimeOnlyFormat = nameof(TimeOnlyFormat); - } + /// The syntax identifier for strings containing time format specifiers. + public const string TimeOnlyFormat = nameof(TimeOnlyFormat); } - -#endif diff --git a/DateTimeOnly/Helpers/ThrowHelper.cs b/DateTimeOnly/Helpers/ThrowHelper.cs index d139c0d..c69b935 100644 --- a/DateTimeOnly/Helpers/ThrowHelper.cs +++ b/DateTimeOnly/Helpers/ThrowHelper.cs @@ -4,34 +4,33 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -namespace System +namespace System; + +internal static class ThrowHelper { - internal static class ThrowHelper - { - [DoesNotReturn] - internal static void ThrowArgumentOutOfRange_DayNumber(int dayNumber) => - throw new ArgumentOutOfRangeException(nameof(dayNumber), dayNumber, SR.ArgumentOutOfRange_DayNumber); + [DoesNotReturn] + internal static void ThrowArgumentOutOfRange_DayNumber(int dayNumber) => + throw new ArgumentOutOfRangeException(nameof(dayNumber), dayNumber, SR.ArgumentOutOfRange_DayNumber); - [DoesNotReturn] - internal static void ThrowArgumentOutOfRange_BadHourMinuteSecond() => - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); + [DoesNotReturn] + internal static void ThrowArgumentOutOfRange_BadHourMinuteSecond() => + throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); - [DoesNotReturn] - internal static void ThrowArgumentNullException(ExceptionArgument argument) => - throw new ArgumentNullException(GetArgumentName(argument)); + [DoesNotReturn] + internal static void ThrowArgumentNullException(ExceptionArgument argument) => + throw new ArgumentNullException(GetArgumentName(argument)); - private static string GetArgumentName(ExceptionArgument argument) + private static string GetArgumentName(ExceptionArgument argument) + { + switch (argument) { - switch (argument) - { - case ExceptionArgument.s: - return "s"; - case ExceptionArgument.format: - return "format"; - default: - Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); - return ""; - } + case ExceptionArgument.s: + return "s"; + case ExceptionArgument.format: + return "format"; + default: + Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); + return ""; } } } diff --git a/DateTimeOnly/ISpanFormattable.cs b/DateTimeOnly/ISpanFormattable.cs index f479217..6d087b7 100644 --- a/DateTimeOnly/ISpanFormattable.cs +++ b/DateTimeOnly/ISpanFormattable.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// ReSharper disable All + namespace System { /// Provides functionality to format the string representation of an object into a span. diff --git a/DateTimeOnly/TimeOnly.cs b/DateTimeOnly/TimeOnly.cs index 28bd490..017ff25 100644 --- a/DateTimeOnly/TimeOnly.cs +++ b/DateTimeOnly/TimeOnly.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// ReSharper disable All + using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Numerics; @@ -521,7 +523,7 @@ private static ParseFailureKind TryParseInternal(ReadOnlySpan s, IFormatPr DateTimeResult dtResult = default; - dtResult.Init(s); + DateTimeResult.Init(s); if (!DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult)) { @@ -590,7 +592,7 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, Read } DateTimeResult dtResult = default; - dtResult.Init(s); + DateTimeResult.Init(s); if (!DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult)) { @@ -671,7 +673,7 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, stri // Create a new result each time to ensure the runs are independent. Carry through // flags from the caller and return the result. DateTimeResult dtResult = default; - dtResult.Init(s); + DateTimeResult.Init(s); if (DateTimeParse.TryParseExact(s, format.AsSpan(), dtfiToUse, style, ref dtResult) && ((dtResult.flags & ParseFlagsTimeMask) == 0)) { result = new TimeOnly(dtResult.parsedDate.TimeOfDay.Ticks);