diff --git a/FrameworkFeatureConstants.props b/FrameworkFeatureConstants.props index e6a8d50e..cd17d346 100644 --- a/FrameworkFeatureConstants.props +++ b/FrameworkFeatureConstants.props @@ -12,6 +12,9 @@ $(DefineConstants);STACK_TRACE_HIDDEN_SUPPORTED;DATE_ONLY_SUPPORTED;TIME_ONLY_SUPPORTED;PRIORITY_QUEUE;TRY_GET_NON_ENUMERATED_COUNT;HTTP_HEADERS_NON_VALIDATED;ELEMENT_AT_INDEX + + $(DefineConstants);GENERIC_MATH;GENERIC_PARSEABLE + $(DefineConstants);RANDOM_SHUFFLE diff --git a/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Generic.cs b/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Generic.cs new file mode 100644 index 00000000..d6277843 --- /dev/null +++ b/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Generic.cs @@ -0,0 +1,36 @@ +#if GENERIC_PARSEABLE +using System.Globalization; + +namespace Funcky.Test.Extensions.ParseExtensions; + +public sealed partial class ParseExtensionsTest +{ + [Theory] + [MemberData(nameof(ParseableDoubleNumbers))] + public void ParseGenericStringReturnsTheExpectedDouble(Option expected, string input) + { + Assert.Equal(expected, input.ParseNumberOrNone(NumberStyles.Number, null)); + Assert.Equal(expected, input.ParseOrNone(null)); + } + + [Theory] + [MemberData(nameof(ParseableDoubleNumbers))] + public void ParseGenericSpanReturnsTheExpectedDouble(Option expected, string input) + { + Assert.Equal(expected, input.AsSpan().ParseNumberOrNone(NumberStyles.Number, null)); + Assert.Equal(expected, input.AsSpan().ParseOrNone(null)); + } + + public static TheoryData, string> ParseableDoubleNumbers() + => new() + { + { Option.Some(1.0), "1.0" }, + { Option.Some(3.145), "3.145" }, + { Option.Some(0.5), ".5" }, + { Option.Some(1.0), "1.0" }, + { Option.Some(42.0), "42" }, + { Option.None, string.Empty }, + { Option.None, "no-number" }, + }; +} +#endif diff --git a/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Version.cs b/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Version.cs index 7f8fb5e5..67e38f40 100644 --- a/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Version.cs +++ b/Funcky.Test/Extensions/ParseExtensions/ParseExtensionsTest.Version.cs @@ -15,7 +15,7 @@ public void ParseVersionIsTheSameAsTryParseForValidVersions(string input) FunctionalAssert.Some(expected!, input.ParseVersionOrNone()); } - #if PARSE_READ_ONLY_SPAN_SUPPORTED +#if PARSE_READ_ONLY_SPAN_SUPPORTED [Theory] [InlineData("1.0")] [InlineData("1.0.0")] @@ -26,7 +26,7 @@ public void ParseVersionIsTheSameAsTryParseForValidVersionsWithReadOnlySpan(stri Assert.True(Version.TryParse(inputSpan, out var expected)); FunctionalAssert.Some(expected!, inputSpan.ParseVersionOrNone()); } - #endif +#endif [Property] public Property ParseVersionIsTheSameAsTryParse(string input) @@ -38,7 +38,7 @@ public Property ParseVersionIsTheSameAsTryParse(string input) return result.ToProperty(); } - #if PARSE_READ_ONLY_SPAN_SUPPORTED +#if PARSE_READ_ONLY_SPAN_SUPPORTED [Property] public Property ParseVersionIsTheSameAsTryParseWithReadOnlySpan(string input) { @@ -49,5 +49,5 @@ public Property ParseVersionIsTheSameAsTryParseWithReadOnlySpan(string input) : parsed.Match(none: true, some: False); return result.ToProperty(); } - #endif +#endif } diff --git a/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericNumber.cs b/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericNumber.cs new file mode 100644 index 00000000..8acc0e71 --- /dev/null +++ b/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericNumber.cs @@ -0,0 +1,20 @@ +#if GENERIC_MATH +using System.Globalization; +using System.Numerics; + +namespace Funcky.Extensions; +public static partial class ParseExtensions +{ + public static Option ParseNumberOrNone(this string value, NumberStyles style, IFormatProvider? provider) + where TNumber : INumberBase + => TNumber.TryParse(value, style, provider, out var result) + ? result + : Option.None; + + public static Option ParseNumberOrNone(this ReadOnlySpan value, NumberStyles style, IFormatProvider? provider) + where TNumber : INumberBase + => TNumber.TryParse(value, style, provider, out var result) + ? result + : Option.None; +} +#endif diff --git a/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs b/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs new file mode 100644 index 00000000..d8cb3572 --- /dev/null +++ b/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs @@ -0,0 +1,18 @@ +#if GENERIC_PARSEABLE +namespace Funcky.Extensions; + +public static partial class ParseExtensions +{ + public static Option ParseOrNone(this ReadOnlySpan value, IFormatProvider? provider) + where TParseable : ISpanParsable + => TParseable.TryParse(value, provider, out var result) + ? result + : Option.None; + + public static Option ParseOrNone(this string? value, IFormatProvider? provider) + where TParseable : IParsable + => TParseable.TryParse(value, provider, out var result) + ? result + : Option.None; +} +#endif diff --git a/Funcky/PublicAPI.Unshipped.txt b/Funcky/PublicAPI.Unshipped.txt index 99809c74..5a25287e 100644 --- a/Funcky/PublicAPI.Unshipped.txt +++ b/Funcky/PublicAPI.Unshipped.txt @@ -10,5 +10,9 @@ Funcky.Monads.Result.InspectError(System.Action Funcky.Monads.Result.OrElse(Funcky.Monads.Result fallback) -> Funcky.Monads.Result Funcky.Monads.Result.OrElse(System.Func>! fallback) -> Funcky.Monads.Result static Funcky.Extensions.EnumeratorExtensions.MoveNextOrNone(this System.Collections.Generic.IEnumerator! enumerator) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseNumberOrNone(this string! value, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseNumberOrNone(this System.ReadOnlySpan value, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseOrNone(this string? value, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseOrNone(this System.ReadOnlySpan value, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.StringExtensions.Chunk(this string! source, int size) -> System.Collections.Generic.IEnumerable! static Funcky.Extensions.StringExtensions.SlidingWindow(this string! source, int width) -> System.Collections.Generic.IEnumerable!