diff --git a/src/Optional.Async.Tests/AsyncEitherTests.cs b/src/Optional.Async.Tests/AsyncEitherTests.cs index 11ceaa6..de7565c 100644 --- a/src/Optional.Async.Tests/AsyncEitherTests.cs +++ b/src/Optional.Async.Tests/AsyncEitherTests.cs @@ -1,10 +1,80 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Threading.Tasks; namespace Optional.Async.Tests { [TestClass] public class AsyncEitherTests { + [TestMethod] + public async Task AsyncEither_SomeNotNullAsync() + { + // Arrange + var task = Task.FromResult(null); + var exception = "A truly exceptional string :)"; + + // Act + var result = await task.SomeNotNullAsync(exception); + + // Assert + var expectedResult = (await task).SomeNotNull(exception); + + result.Should().Be(expectedResult); + } + + [TestMethod] + public async Task AsyncEither_SomeWhenAsync() + { + // Arrange + var value = ValueGenerator.RandomString(); + var task = Task.FromResult(value); + + Func predicate = s => s == "This should definitely return false"; + var error = "Error"; + + // Act + var result = await task.SomeWhenAsync(predicate, error); + + // Assert + var expectedResult = (await task).SomeWhen(predicate, error); + + result.Should().Be(expectedResult); + } + + [TestMethod] + public async Task AsyncEither_SomeWhenAsync_With_ExceptionFactory() + { + // Arrange + var value = ValueGenerator.RandomString(); + var task = Task.FromResult(value); + + Func predicate = s => s == "This should definitely return false"; + Func exceptionFactory = _ => 10; + + // Act + var result = await task.SomeWhenAsync(predicate, exceptionFactory); + + // Assert + var expectedResult = (await task).SomeWhen(predicate, exceptionFactory); + + result.Should().Be(expectedResult); + } + + [TestMethod] + public async Task AsyncEither_ToAsync() + { + // Arrange + var option = 10.Some(); + + // Act + var result = option.ToAsync(); + + // Assert + (await result).Should().Be(option); + } + [TestMethod] public void AsyncEither_MapAsync() { diff --git a/src/Optional.Async.Tests/AsyncMaybeTests.cs b/src/Optional.Async.Tests/AsyncMaybeTests.cs index 38223a6..fcb0474 100644 --- a/src/Optional.Async.Tests/AsyncMaybeTests.cs +++ b/src/Optional.Async.Tests/AsyncMaybeTests.cs @@ -1,6 +1,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Optional.Unsafe; +using System; using System.Threading; using System.Threading.Tasks; @@ -9,6 +10,89 @@ namespace Optional.Async.Tests [TestClass] public class AsyncMaybeTests { + [TestMethod] + public async Task AsyncMaybe_ToAsync() + { + // Arrange + var option = 10.Some(); + + // Act + var result = option.ToAsync(); + + // Assert + (await result).Should().Be(option); + } + + [TestMethod] + public async Task AsyncMaybe_FlatMapAsync_To_Exceptional() + { + // Arrange + var option = Option.None(); + var exceptionalOption = Option.None(ValueGenerator.RandomString()); + var error = "Error"; + + // Act + var result = await option.FlatMapAsync(_ => Task.FromResult(exceptionalOption), error); + + // Assert + var expected = Option.None(error); + + result.Should().Be(expected); + } + + [TestMethod] + public async Task AsyncMaybe_FilterAsync_Should_Return_Exception() + { + // Arrange + var optionTask = ValueGenerator.DelayedSome(10); + + Func> predicate = _ => Task.FromResult(false); + var exception = "Error"; + + // Act + var result = await optionTask.FilterAsync(predicate, exception); + + // Assert + var expected = Option.None(exception); + + result.Should().Be(expected); + } + + [TestMethod] + public async Task AsyncMaybe_FilterAsync_Should_Return_Value() + { + // Arrange + var value = 10; + var optionTask = ValueGenerator.DelayedSome(value); + + Func> predicate = _ => Task.FromResult(true); + var exception = "Error"; + + // Act + var result = await optionTask.FilterAsync(predicate, exception); + + // Assert + var expected = Option.Some(value); + + result.Should().Be(expected); + } + + [TestMethod] + public async Task AsyncMaybe_SomeNotNull() + { + // Arrange + object nullObject = null; + var nullTask = Task.FromResult(nullObject); + + // Act + var result = await nullTask.SomeNotNullAsync(); + + // Assert + var expected = nullObject.SomeNotNull(); + + result.Should().Be(expected); + } + [TestMethod] public async Task AsyncMaybe_CanMapAsync() { diff --git a/src/Optional.Async.Tests/ValueGenerator.cs b/src/Optional.Async.Tests/ValueGenerator.cs index d90c244..9ca29e6 100644 --- a/src/Optional.Async.Tests/ValueGenerator.cs +++ b/src/Optional.Async.Tests/ValueGenerator.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace Optional.Async.Tests { @@ -10,6 +11,10 @@ public static async Task DelayedValue(T value) return value; } + public static string RandomString() => Guid.NewGuid().ToString(); + public static Func> AsyncOperation(TResult result) => _ => Task.FromResult(result); + public static Func SynchronousOperation(TResult result) => _ => result; + public static Task> DelayedSome(T value) => DelayedValue(value.Some()); public static Task> DelayedSome(T value) => DelayedValue(value.Some()); diff --git a/src/Optional.Async/OptionTaskExtensions_Either.cs b/src/Optional.Async/OptionTaskExtensions_Either.cs index ff90197..e94a62d 100644 --- a/src/Optional.Async/OptionTaskExtensions_Either.cs +++ b/src/Optional.Async/OptionTaskExtensions_Either.cs @@ -5,68 +5,81 @@ namespace Optional.Async { public static partial class OptionTaskExtensions { - public static Task> MapAsync(this Option option, Func> mapping) + public static async Task> ElseAsync(this Option option, Func>> alternativeOptionFactory) { - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); - return option.Map(mapping).Match( - some: async valueTask => - { - if (valueTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); - var value = await valueTask.ConfigureAwait(continueOnCapturedContext: false); - return value.Some(); - }, - none: exception => Task.FromResult(Option.None(exception)) - ); + if (option.HasValue) return option; + + var alternativeOptionTask = alternativeOptionFactory(); + if (alternativeOptionTask == null) throw new InvalidOperationException($"{nameof(alternativeOptionFactory)} must not return a null task."); + + return await alternativeOptionTask.ConfigureAwait(continueOnCapturedContext: false); } - public static async Task> MapAsync(this Task> optionTask, Func mapping, bool executeOnCapturedContext = false) + public static async Task> ElseAsync(this Task> optionTask, Func> alternativeOptionFactory, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.Map(mapping); + return option.Else(alternativeOptionFactory); } - public static async Task> MapAsync(this Task> optionTask, Func> mapping, bool executeOnCapturedContext = false) + public static async Task> ElseAsync(this Task> optionTask, Func>> alternativeOptionFactory, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.MapAsync(mapping).ConfigureAwait(continueOnCapturedContext: false); + return await option.ElseAsync(alternativeOptionFactory).ConfigureAwait(continueOnCapturedContext: false); } - public static Task> MapExceptionAsync(this Option option, Func> mapping) + public static Task> FilterAsync(this Option option, Func> predicate, TException exception) => + option.FilterAsync(predicate, () => exception); + + public static Task> FilterAsync(this Option option, Func> predicate, Func exceptionFactory) { - return option.MapException(mapping).Match( - some: value => Task.FromResult(Option.Some(value)), - none: async exceptionTask => + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (exceptionFactory == null) throw new ArgumentNullException(nameof(exceptionFactory)); + + return option.Match( + some: async value => { - if (exceptionTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); - var exception = await exceptionTask.ConfigureAwait(continueOnCapturedContext: false); - return Option.None(exception); - } + var predicateTask = predicate(value); + if (predicateTask == null) throw new InvalidOperationException($"{nameof(predicate)} must not return a null task."); + + var condition = await predicateTask.ConfigureAwait(continueOnCapturedContext: false); + return option.Filter(condition, exceptionFactory); + }, + none: _ => Task.FromResult(option) ); } - public static async Task> MapExceptionAsync(this Task> optionTask, Func mapping, bool executeOnCapturedContext = false) + public static Task> FilterAsync(this Task> optionTask, Func predicate, TException exception, bool executeOnCapturedContext = false) => + optionTask.FilterAsync(predicate, () => exception, executeOnCapturedContext); + + public static async Task> FilterAsync(this Task> optionTask, Func predicate, Func exceptionFactory, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (exceptionFactory == null) throw new ArgumentNullException(nameof(exceptionFactory)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.MapException(mapping); + return option.Filter(predicate, exceptionFactory); } - public static async Task> MapExceptionAsync(this Task> optionTask, Func> mapping, bool executeOnCapturedContext = false) + public static Task> FilterAsync(this Task> optionTask, Func> predicate, TException exception, bool executeOnCapturedContext = false) => + optionTask.FilterAsync(predicate, () => exception, executeOnCapturedContext); + + public static async Task> FilterAsync(this Task> optionTask, Func> predicate, Func exceptionFactory, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (exceptionFactory == null) throw new ArgumentNullException(nameof(exceptionFactory)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.MapExceptionAsync(mapping).ConfigureAwait(false); + return await option.FilterAsync(predicate, exceptionFactory).ConfigureAwait(continueOnCapturedContext: false); } public static Task> FlatMapAsync(this Option option, Func>> mapping) @@ -143,51 +156,76 @@ public static async Task> FlatMapAsync> FilterAsync(this Option option, Func> predicate, TException exception) => - option.FilterAsync(predicate, () => exception); + public static async Task> FlattenAsync(this Task, TException>> optionTask) + { + if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - public static Task> FilterAsync(this Option option, Func> predicate, Func exceptionFactory) + var option = await optionTask.ConfigureAwait(continueOnCapturedContext: false); + return option.Flatten(); + } + + public static Task> MapAsync(this Option option, Func> mapping) { - if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - if (exceptionFactory == null) throw new ArgumentNullException(nameof(exceptionFactory)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); - return option.Match( - some: async value => + return option.Map(mapping).Match( + some: async valueTask => { - var predicateTask = predicate(value); - if (predicateTask == null) throw new InvalidOperationException($"{nameof(predicate)} must not return a null task."); - - var condition = await predicateTask.ConfigureAwait(continueOnCapturedContext: false); - return option.Filter(condition, exceptionFactory); + if (valueTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); + var value = await valueTask.ConfigureAwait(continueOnCapturedContext: false); + return value.Some(); }, - none: _ => Task.FromResult(option) + none: exception => Task.FromResult(Option.None(exception)) ); } - public static Task> FilterAsync(this Task> optionTask, Func predicate, TException exception, bool executeOnCapturedContext = false) => - optionTask.FilterAsync(predicate, () => exception, executeOnCapturedContext); + public static async Task> MapAsync(this Task> optionTask, Func mapping, bool executeOnCapturedContext = false) + { + if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); - public static async Task> FilterAsync(this Task> optionTask, Func predicate, Func exceptionFactory, bool executeOnCapturedContext = false) + var option = await optionTask.ConfigureAwait(executeOnCapturedContext); + return option.Map(mapping); + } + + public static async Task> MapAsync(this Task> optionTask, Func> mapping, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - if (exceptionFactory == null) throw new ArgumentNullException(nameof(exceptionFactory)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.Filter(predicate, exceptionFactory); + return await option.MapAsync(mapping).ConfigureAwait(continueOnCapturedContext: false); } - public static Task> FilterAsync(this Task> optionTask, Func> predicate, TException exception, bool executeOnCapturedContext = false) => - optionTask.FilterAsync(predicate, () => exception, executeOnCapturedContext); + public static Task> MapExceptionAsync(this Option option, Func> mapping) + { + return option.MapException(mapping).Match( + some: value => Task.FromResult(Option.Some(value)), + none: async exceptionTask => + { + if (exceptionTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); + var exception = await exceptionTask.ConfigureAwait(continueOnCapturedContext: false); + return Option.None(exception); + } + ); + } - public static async Task> FilterAsync(this Task> optionTask, Func> predicate, Func exceptionFactory, bool executeOnCapturedContext = false) + public static async Task> MapExceptionAsync(this Task> optionTask, Func mapping, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - if (exceptionFactory == null) throw new ArgumentNullException(nameof(exceptionFactory)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.FilterAsync(predicate, exceptionFactory).ConfigureAwait(continueOnCapturedContext: false); + return option.MapException(mapping); + } + + public static async Task> MapExceptionAsync(this Task> optionTask, Func> mapping, bool executeOnCapturedContext = false) + { + if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + + var option = await optionTask.ConfigureAwait(executeOnCapturedContext); + return await option.MapExceptionAsync(mapping).ConfigureAwait(false); } public static Task> NotNullAsync(this Task> optionTask, TException exception) => @@ -231,35 +269,23 @@ public static async Task> OrAsync(this Task return await option.OrAsync(alternativeFactory).ConfigureAwait(continueOnCapturedContext: false); } - public static async Task> ElseAsync(this Option option, Func>> alternativeOptionFactory) - { - if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); + public static async Task> SomeNotNullAsync(this Task task, TException exception) => + (await task).SomeNotNull(exception); - if (option.HasValue) return option; - - var alternativeOptionTask = alternativeOptionFactory(); - if (alternativeOptionTask == null) throw new InvalidOperationException($"{nameof(alternativeOptionFactory)} must not return a null task."); - - return await alternativeOptionTask.ConfigureAwait(continueOnCapturedContext: false); - } - - public static async Task> ElseAsync(this Task> optionTask, Func> alternativeOptionFactory, bool executeOnCapturedContext = false) + public static async Task> SomeWhenAsync(this Task valueTask, Func predicate, Func exceptionFactory) { - if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); + var value = await valueTask; + var result = predicate(value); - var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.Else(alternativeOptionFactory); + return result ? + value.Some() : + Option.None(exceptionFactory(value)); } - public static async Task> ElseAsync(this Task> optionTask, Func>> alternativeOptionFactory, bool executeOnCapturedContext = false) - { - if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); + public static async Task> SomeWhenAsync(this Task task, Func predicate, TException exception) => + (await task).SomeWhen(predicate, exception); - var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.ElseAsync(alternativeOptionFactory).ConfigureAwait(continueOnCapturedContext: false); - } + public static Task> ToAsync(this Option option) => Task.FromResult(option); public static async Task> WithoutExceptionAsync(this Task> optionTask) { @@ -268,13 +294,5 @@ public static async Task> WithoutExceptionAsync(this Ta var option = await optionTask.ConfigureAwait(false); return option.WithoutException(); } - - public static async Task> FlattenAsync(this Task, TException>> optionTask) - { - if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - - var option = await optionTask.ConfigureAwait(continueOnCapturedContext: false); - return option.Flatten(); - } } -} +} \ No newline at end of file diff --git a/src/Optional.Async/OptionTaskExtensions_Maybe.cs b/src/Optional.Async/OptionTaskExtensions_Maybe.cs index ae70a15..b4d9a43 100644 --- a/src/Optional.Async/OptionTaskExtensions_Maybe.cs +++ b/src/Optional.Async/OptionTaskExtensions_Maybe.cs @@ -5,37 +5,86 @@ namespace Optional.Async { public static partial class OptionTaskExtensions { - public static Task> MapAsync(this Option option, Func> mapping) + public static async Task> ElseAsync(this Option option, Func>> alternativeOptionFactory) { - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); - return option.Map(mapping).Match( - some: async valueTask => + if (option.HasValue) return option; + + var alternativeOptionTask = alternativeOptionFactory(); + if (alternativeOptionTask == null) throw new InvalidOperationException($"{nameof(alternativeOptionFactory)} must not return a null task."); + + return await alternativeOptionTask.ConfigureAwait(continueOnCapturedContext: false); + } + + public static async Task> ElseAsync(this Task> optionTask, Func> alternativeOptionFactory, bool executeOnCapturedContext = false) + { + if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); + if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); + + var option = await optionTask.ConfigureAwait(executeOnCapturedContext); + return option.Else(alternativeOptionFactory); + } + + public static async Task> ElseAsync(this Task> optionTask, Func>> alternativeOptionFactory, bool executeOnCapturedContext = false) + { + if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); + if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); + + var option = await optionTask.ConfigureAwait(executeOnCapturedContext); + return await option.ElseAsync(alternativeOptionFactory).ConfigureAwait(continueOnCapturedContext: false); + } + + public static async Task> FilterAsync(this Task> optionTask, Func> predicate, TException exception) => + await (await optionTask).FilterAsync(predicate).WithExceptionAsync(exception); + + public static Task> FilterAsync(this Option option, Func> predicate) + { + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + + return option.Match( + some: async value => { - if (valueTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); - var value = await valueTask.ConfigureAwait(continueOnCapturedContext: false); - return value.Some(); + var predicateTask = predicate(value); + if (predicateTask == null) throw new InvalidOperationException($"{nameof(predicate)} must not return a null task."); + + var condition = await predicateTask.ConfigureAwait(continueOnCapturedContext: false); + return option.Filter(condition); }, - none: () => Task.FromResult(Option.None()) + none: () => Task.FromResult(option) ); } - public static async Task> MapAsync(this Task> optionTask, Func mapping, bool executeOnCapturedContext = false) + public static async Task> FilterAsync(this Task> optionTask, Func predicate, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.Map(mapping); + return option.Filter(predicate); } - public static async Task> MapAsync(this Task> optionTask, Func> mapping, bool executeOnCapturedContext = false) + public static async Task> FilterAsync(this Task> optionTask, Func> predicate, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.MapAsync(mapping).ConfigureAwait(continueOnCapturedContext: false); + return await option.FilterAsync(predicate).ConfigureAwait(continueOnCapturedContext: false); + } + + public static Task> FlatMapAsync(this Option option, Func>> mapping, TException exception) + { + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + + return option.Map(mapping).Match( + some: resultOptionTask => + { + if (resultOptionTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); + return resultOptionTask; + }, + none: () => Task.FromResult(Option.None(exception)) + ); } public static Task> FlatMapAsync(this Option option, Func>> mapping) @@ -100,39 +149,45 @@ public static async Task> FlatMapAsync(t return await option.FlatMapAsync(mapping).ConfigureAwait(continueOnCapturedContext: false); } - public static Task> FilterAsync(this Option option, Func> predicate) + public static async Task> FlattenAsync(this Task>> optionTask) { - if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - return option.Match( - some: async value => - { - var predicateTask = predicate(value); - if (predicateTask == null) throw new InvalidOperationException($"{nameof(predicate)} must not return a null task."); + var option = await optionTask.ConfigureAwait(continueOnCapturedContext: false); + return option.Flatten(); + } - var condition = await predicateTask.ConfigureAwait(continueOnCapturedContext: false); - return option.Filter(condition); + public static Task> MapAsync(this Option option, Func> mapping) + { + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); + + return option.Map(mapping).Match( + some: async valueTask => + { + if (valueTask == null) throw new InvalidOperationException($"{nameof(mapping)} must not return a null task."); + var value = await valueTask.ConfigureAwait(continueOnCapturedContext: false); + return value.Some(); }, - none: () => Task.FromResult(option) + none: () => Task.FromResult(Option.None()) ); } - public static async Task> FilterAsync(this Task> optionTask, Func predicate, bool executeOnCapturedContext = false) + public static async Task> MapAsync(this Task> optionTask, Func mapping, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.Filter(predicate); + return option.Map(mapping); } - public static async Task> FilterAsync(this Task> optionTask, Func> predicate, bool executeOnCapturedContext = false) + public static async Task> MapAsync(this Task> optionTask, Func> mapping, bool executeOnCapturedContext = false) { if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (mapping == null) throw new ArgumentNullException(nameof(mapping)); var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.FilterAsync(predicate).ConfigureAwait(continueOnCapturedContext: false); + return await option.MapAsync(mapping).ConfigureAwait(continueOnCapturedContext: false); } public static Task> NotNullAsync(this Task> optionTask) @@ -172,35 +227,9 @@ public static async Task> OrAsync(this Task> optionTask, return await option.OrAsync(alternativeFactory).ConfigureAwait(continueOnCapturedContext: false); } - public static async Task> ElseAsync(this Option option, Func>> alternativeOptionFactory) - { - if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); - - if (option.HasValue) return option; - - var alternativeOptionTask = alternativeOptionFactory(); - if (alternativeOptionTask == null) throw new InvalidOperationException($"{nameof(alternativeOptionFactory)} must not return a null task."); - - return await alternativeOptionTask.ConfigureAwait(continueOnCapturedContext: false); - } - - public static async Task> ElseAsync(this Task> optionTask, Func> alternativeOptionFactory, bool executeOnCapturedContext = false) - { - if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); - - var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return option.Else(alternativeOptionFactory); - } + public static async Task> SomeNotNullAsync(this Task task) => (await task).SomeNotNull(); - public static async Task> ElseAsync(this Task> optionTask, Func>> alternativeOptionFactory, bool executeOnCapturedContext = false) - { - if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - if (alternativeOptionFactory == null) throw new ArgumentNullException(nameof(alternativeOptionFactory)); - - var option = await optionTask.ConfigureAwait(executeOnCapturedContext); - return await option.ElseAsync(alternativeOptionFactory).ConfigureAwait(continueOnCapturedContext: false); - } + public static Task> ToAsync(this Option option) => Task.FromResult(option); public static Task> WithExceptionAsync(this Task> optionTask, TException exception) => optionTask.WithExceptionAsync(() => exception); @@ -213,13 +242,5 @@ public static async Task> WithExceptionAsync> FlattenAsync(this Task>> optionTask) - { - if (optionTask == null) throw new ArgumentNullException(nameof(optionTask)); - - var option = await optionTask.ConfigureAwait(continueOnCapturedContext: false); - return option.Flatten(); - } } -} +} \ No newline at end of file diff --git a/src/Optional.sln b/src/Optional.sln index 12eb394..ecbcc98 100644 --- a/src/Optional.sln +++ b/src/Optional.sln @@ -17,7 +17,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Optional.Sandbox", "Optiona EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Optional.Samples", "Optional.Samples\Optional.Samples.csproj", "{02A7D729-3C90-45E2-8183-FC10BA760A80}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Optional.Async.Tests", "Optional.Async.Tests\Optional.Async.Tests.csproj", "{89D005BD-46B2-4E79-8267-AAB77C818998}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Optional.Async.Tests", "Optional.Async.Tests\Optional.Async.Tests.csproj", "{89D005BD-46B2-4E79-8267-AAB77C818998}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,7 +34,6 @@ Global {A61CE069-370F-474A-B925-C17B74F9198C}.Release|Any CPU.ActiveCfg = Release|Any CPU {A61CE069-370F-474A-B925-C17B74F9198C}.Release|Any CPU.Build.0 = Release|Any CPU {F00BED6E-4808-48EE-B14E-092182080EB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F00BED6E-4808-48EE-B14E-092182080EB3}.Debug|Any CPU.Build.0 = Debug|Any CPU {F00BED6E-4808-48EE-B14E-092182080EB3}.Release|Any CPU.ActiveCfg = Release|Any CPU {F00BED6E-4808-48EE-B14E-092182080EB3}.Release|Any CPU.Build.0 = Release|Any CPU {12606143-9C9B-4A92-81D5-CEA814AC64AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -46,7 +45,6 @@ Global {9ADFB283-560D-4FD1-981C-3348BF1DDAF4}.Release|Any CPU.ActiveCfg = Release|Any CPU {9ADFB283-560D-4FD1-981C-3348BF1DDAF4}.Release|Any CPU.Build.0 = Release|Any CPU {02A7D729-3C90-45E2-8183-FC10BA760A80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {02A7D729-3C90-45E2-8183-FC10BA760A80}.Debug|Any CPU.Build.0 = Debug|Any CPU {02A7D729-3C90-45E2-8183-FC10BA760A80}.Release|Any CPU.ActiveCfg = Release|Any CPU {02A7D729-3C90-45E2-8183-FC10BA760A80}.Release|Any CPU.Build.0 = Release|Any CPU {89D005BD-46B2-4E79-8267-AAB77C818998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU