From a55f11533830a3451333a5ce88a9f40f97660bd2 Mon Sep 17 00:00:00 2001 From: Jimmy Byrd Date: Sat, 17 Dec 2022 15:40:00 -0500 Subject: [PATCH] Adds helpers to CancellableTaskResult --- .../CancellableTaskResultCE.fs | 78 ++++++++++++++++ .../CancellableTaskResultCE.fs | 91 ++++++++++++++++++- 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs index 73e8b059..53b5eb29 100644 --- a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs +++ b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs @@ -770,3 +770,81 @@ module CancellableTaskResultCE = true ) ) + + /// Lifts an item to a CancellableTaskResult. + /// The item to be the result of the CancellableTaskResult. + /// A CancellableTaskResult with the item as the result. + let inline singleton (item: 'item) : CancellableTaskResult<'item, 'Error> = + fun _ -> Task.FromResult(Ok item) + + + /// Allows chaining of CancellableTaskResult. + /// The continuation. + /// The value. + /// The result of the binder. + let inline bind + ([] binder: 'input -> CancellableTaskResult<'output, 'error>) + ([] cTask: CancellableTaskResult<'input, 'error>) + = + cancellableTaskResult { + let! cResult = cTask + return! binder cResult + } + + /// Allows chaining of CancellableTaskResult. + /// The continuation. + /// The value. + /// The result of the mapper wrapped in a CancellableTaskResult. + let inline map + ([] mapper: 'input -> 'output) + ([] cTask: CancellableTaskResult<'input, 'error>) + = + cancellableTaskResult { + let! cResult = cTask + return mapper cResult + } + + /// Allows chaining of CancellableTaskResult. + /// A function wrapped in a CancellableTaskResult + /// The value. + /// The result of the applicable. + let inline apply + ([] applicable: CancellableTaskResult<'input -> 'output, 'error>) + ([] cTask: CancellableTaskResult<'input, 'error>) + = + cancellableTaskResult { + let! applier = applicable + let! cResult = cTask + return applier cResult + } + + /// Takes two CancellableTaskResult, starts them serially in order of left to right, and returns a tuple of the pair. + /// The left value. + /// The right value. + /// A tuple of the parameters passed in + let inline zip + ([] left: CancellableTaskResult<'left, 'error>) + ([] right: CancellableTaskResult<'right, 'error>) + = + cancellableTaskResult { + let! r1 = left + let! r2 = right + return r1, r2 + } + + /// Takes two CancellableTaskResult, starts them concurrently, and returns a tuple of the pair. + /// The left value. + /// The right value. + /// A tuple of the parameters passed in. + let inline parallelZip + ([] left: CancellableTaskResult<'left, 'error>) + ([] right: CancellableTaskResult<'right, 'error>) + = + cancellableTaskResult { + let! ct = getCancellationToken () + let r1 = left ct + let r2 = right ct + let! r1 = r1 + let! r2 = r2 + return r1, r2 + } diff --git a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs index 23a92a74..a15a3a2d 100644 --- a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs @@ -56,7 +56,7 @@ module CancellableTaskResultCE = member this.Dispose() = () } - [] + let cancellableTaskResultBuilderTests = testList "CancellableTaskResultBuilder" [ testList "Return" [ @@ -923,3 +923,92 @@ module CancellableTaskResultCE = ] ] + + let functionTests = + testList "functions" [ + testList "singleton" [ + testCaseAsync "Simple" + <| async { + let innerCall = CancellableTaskResult.singleton "lol" + + let! someTask = innerCall + + Expect.equal (Ok "lol") someTask "" + } + ] + testList "bind" [ + testCaseAsync "Simple" + <| async { + let innerCall = cancellableTaskResult { return "lol" } + + let! someTask = + innerCall + |> CancellableTaskResult.bind (fun x -> cancellableTaskResult { + return x + "fooo" + } + ) + + Expect.equal (Ok "lolfooo") someTask "" + } + ] + testList "map" [ + testCaseAsync "Simple" + <| async { + let innerCall = cancellableTaskResult { return "lol" } + + let! someTask = + innerCall + |> CancellableTaskResult.map (fun x -> x + "fooo") + + Expect.equal (Ok "lolfooo") someTask "" + } + ] + testList "apply" [ + testCaseAsync "Simple" + <| async { + let innerCall = cancellableTaskResult { return "lol" } + let applier = cancellableTaskResult { return fun x -> x + "fooo" } + + let! someTask = + innerCall + |> CancellableTaskResult.apply applier + + Expect.equal (Ok "lolfooo") someTask "" + } + ] + + testList "zip" [ + testCaseAsync "Simple" + <| async { + let innerCall = cancellableTaskResult { return "fooo" } + let innerCall2 = cancellableTaskResult { return "lol" } + + let! someTask = + innerCall + |> CancellableTaskResult.zip innerCall2 + + Expect.equal (Ok("lol", "fooo")) someTask "" + } + ] + + testList "parZip" [ + testCaseAsync "Simple" + <| async { + let innerCall = cancellableTaskResult { return "fooo" } + let innerCall2 = cancellableTaskResult { return "lol" } + + let! someTask = + innerCall + |> CancellableTaskResult.parallelZip innerCall2 + + Expect.equal (Ok("lol", "fooo")) someTask "" + } + ] + ] + + [] + let cancellableTaskResultTests = + testList "CancellableTaskResult" [ + cancellableTaskResultBuilderTests + functionTests + ]