Skip to content

Commit

Permalink
Updated asyncValidation CE
Browse files Browse the repository at this point in the history
  • Loading branch information
1eyewonder committed Jul 13, 2024
1 parent 6f50643 commit e8e773b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 59 deletions.
79 changes: 25 additions & 54 deletions src/FsToolkit.ErrorHandling/AsyncValidationCE.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,82 +23,53 @@ module AsyncValidationCE =
member inline this.Zero() : AsyncValidation<unit, 'error> = this.Return()

member inline _.Delay
([<InlineIfLambda>] generator: unit -> AsyncValidation<'ok, 'error>)
: unit -> AsyncValidation<'ok, 'error> =
generator

member inline _.Run
([<InlineIfLambda>] generator: unit -> AsyncValidation<'ok, 'error>)
: AsyncValidation<'ok, 'error> =
generator ()
async.Delay generator

member inline this.Combine
(
result: AsyncValidation<unit, 'error>,
[<InlineIfLambda>] binder: unit -> AsyncValidation<'ok, 'error>
validation1: AsyncValidation<unit, 'error>,
validation2: AsyncValidation<'ok, 'error>
) : AsyncValidation<'ok, 'error> =
this.Bind(result, binder)
this.Bind(validation1, (fun () -> validation2))

member inline this.TryWith
member inline _.TryWith
(
[<InlineIfLambda>] generator: unit -> AsyncValidation<'ok, 'error>,
computation: AsyncValidation<'ok, 'error>,
[<InlineIfLambda>] handler: exn -> AsyncValidation<'ok, 'error>
) : AsyncValidation<'ok, 'error> =
async {
return!
try
this.Run generator
with e ->
handler e
}

member inline this.TryFinally
async.TryWith(computation, handler)

member inline _.TryFinally
(
[<InlineIfLambda>] generator: unit -> AsyncValidation<'ok, 'error>,
computation: AsyncValidation<'ok, 'error>,
[<InlineIfLambda>] compensation: unit -> unit
) : AsyncValidation<'ok, 'error> =
async {
return!
try
this.Run generator
finally
compensation ()
}

member inline this.Using
async.TryFinally(computation, compensation)

member inline _.Using
(
resource: 'disposable :> IDisposable,
[<InlineIfLambda>] binder: 'disposable -> AsyncValidation<'okOutput, 'error>
) : AsyncValidation<'okOutput, 'error> =
this.TryFinally(
(fun () -> binder resource),
(fun () ->
if not (obj.ReferenceEquals(resource, null)) then
resource.Dispose()
)
)
async.Using(resource, binder)

member inline this.While
(
[<InlineIfLambda>] guard: unit -> bool,
[<InlineIfLambda>] generator: unit -> AsyncValidation<unit, 'error>
computation: AsyncValidation<unit, 'error>
) : AsyncValidation<unit, 'error> =
let mutable doContinue = true
let mutable result = Ok()

async {
while doContinue
&& guard () do
let! x = generator ()

match x with
| Ok() -> ()
| Error e ->
doContinue <- false
result <- Error e

return result
}
if guard () then
let mutable whileAsync = Unchecked.defaultof<_>

whileAsync <-
this.Bind(computation, (fun () -> if guard () then whileAsync else this.Zero()))

whileAsync
else
this.Zero()


member inline this.For
(
Expand Down
20 changes: 15 additions & 5 deletions tests/FsToolkit.ErrorHandling.Tests/AsyncValidationCE.fs
Original file line number Diff line number Diff line change
Expand Up @@ -279,40 +279,49 @@ let ``AsyncValidationCE try Tests`` =
}
]

let makeDisposable () =
let makeDisposable callback =
{ new System.IDisposable with
member this.Dispose() = ()
member _.Dispose() = callback ()
}

let ``AsyncValidationCE using Tests`` =
testList "AsyncValidationCE using Tests" [
testCaseAsync "use normal disposable"
<| async {
let data = 42
let mutable isFinished = false

let! actual =
asyncValidation {
use d = makeDisposable ()
use d = makeDisposable (fun () -> isFinished <- true)
return data
}

Expect.equal actual (Ok data) "Should be ok"
Expect.equal actual (Result.Ok data) "Should be ok"
Expect.isTrue isFinished ""
}

testCaseAsync "use! normal wrapped disposable"
<| async {
let data = 42
let mutable isFinished = false

let! actual =
asyncValidation {
use! d =
makeDisposable ()
makeDisposable (fun () -> isFinished <- true)
|> Ok

return data
}

Expect.equal actual (Ok data) "Should be ok"
Expect.isTrue isFinished ""
}

#if !FABLE_COMPILER && NETSTANDARD2_1
// Fable can't handle null disposables you get
// TypeError: Cannot read property 'Dispose' of null
testCaseAsync "use null disposable"
<| async {
let data = 42
Expand All @@ -325,6 +334,7 @@ let ``AsyncValidationCE using Tests`` =

Expect.equal actual (Ok data) "Should be ok"
}
#endif
]

let ``AsyncValidationCE loop Tests`` =
Expand Down

0 comments on commit e8e773b

Please sign in to comment.