Skip to content

Commit

Permalink
Merge pull request #119 from natefaubion/avar-updates
Browse files Browse the repository at this point in the history
AVar updates
natefaubion authored Aug 31, 2017
2 parents 9715ea7 + 104129b commit 46749af
Showing 4 changed files with 33 additions and 17 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -212,7 +212,7 @@ The `Control.Monad.Aff.AVar` module contains asynchronous variables, which
are very similar to Haskell's `MVar`.

`AVar`s represent a value that is either full or empty. Calling `takeVar` on
an empty `AVar` will queue until it is filled by a matching `putVar`.
an empty `AVar` will queue until it is filled by a `putVar`.

```purescript
example = do
@@ -230,22 +230,23 @@ example = do
> Got a value: hello
```

Likewise, calling `putVar` will queue until it is taken:
Likewise, calling `putVar` on a filled `AVar` will queue until it is emptied by
a `takeVar`.

```purescript
example = do
var <- makeEmptyVar
var <- makeVar "hello"
_ <- forkAff do
delay (Milliseconds 100.0)
value <- takeVar var
log $ "Got a value: " <> value
putVar var "hello"
log "Value taken"
putVar var "next"
log "Value put"
```
```
(Waits 100ms)
> Value taken
> Got a value: hello
> Value put
```

These combinators (and a few more) can be used as the building blocks for
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@
"purescript-free": "^4.0.1",
"purescript-st": "^3.0.0",
"purescript-type-equality": "^2.1.0",
"purescript-avar": "^1.0.1"
"purescript-avar": "^2.0.0"
},
"devDependencies": {
"purescript-partial": "^1.2.0",
33 changes: 24 additions & 9 deletions src/Control/Monad/Aff/AVar.purs
Original file line number Diff line number Diff line change
@@ -2,7 +2,10 @@ module Control.Monad.Aff.AVar
( module Control.Monad.Eff.AVar
, makeVar
, makeEmptyVar
, status
, isEmptyVar
, isFilledVar
, isKilledVar
, takeVar
, tryTakeVar
, putVar
@@ -15,7 +18,7 @@ module Control.Monad.Aff.AVar
import Prelude
import Control.Monad.Aff (Aff, Canceler(..), makeAff)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.AVar (AVar, AVAR)
import Control.Monad.Eff.AVar (AVar, AVAR, AVarStatus(..), isEmpty, isFilled, isKilled)
import Control.Monad.Eff.AVar as AVar
import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff.Exception (Error)
@@ -32,10 +35,22 @@ makeVar = liftEff <<< AVar.makeVar
makeEmptyVar eff a. Aff (avar AVAR | eff) (AVar a)
makeEmptyVar = liftEff AVar.makeEmptyVar

-- | Synchronously checks whether an AVar currently has a value.
-- | Synchronously checks the status of an AVar.
status eff a. AVar a Aff (avar AVAR | eff) (AVar.AVarStatus a)
status = liftEff <<< AVar.status

-- | Synchronously checks whether an AVar currently is empty.
isEmptyVar eff a. AVar a Aff (avar AVAR | eff) Boolean
isEmptyVar = liftEff <<< AVar.isEmptyVar

-- | Synchronously checks whether an AVar currently has a value.
isFilledVar eff a. AVar a Aff (avar AVAR | eff) Boolean
isFilledVar = liftEff <<< AVar.isFilledVar

-- | Synchronously checks whether an AVar has been killed.
isKilledVar eff a. AVar a Aff (avar AVAR | eff) Boolean
isKilledVar = liftEff <<< AVar.isKilledVar

-- | Takes the AVar value, leaving it empty. If the AVar is already empty,
-- | the callback will be queued until the AVar is filled. Multiple takes will
-- | resolve in order as the AVar fills.
@@ -52,15 +67,15 @@ tryTakeVar = liftEff <<< AVar.tryTakeVar
-- | Sets the value of the AVar. If the AVar is already filled, it will be
-- | queued until the value is emptied. Multiple puts will resolve in order as
-- | the AVar becomes available.
putVar eff a. AVar a a Aff (avar AVAR | eff) Unit
putVar avar value = makeAff \k → do
c ← AVar.putVar avar value k
putVar eff a. a AVar a Aff (avar AVAR | eff) Unit
putVar value avar = makeAff \k → do
c ← AVar.putVar value avar k
pure (toCanceler c)

-- | Attempts to synchronously fill an AVar. If the AVar is already filled,
-- | this will do nothing. Returns true or false depending on if it succeeded.
tryPutVar eff a. AVar a a Aff (avar AVAR | eff) Boolean
tryPutVar avar = liftEff <<< AVar.tryPutVar avar
tryPutVar eff a. a AVar a Aff (avar AVAR | eff) Boolean
tryPutVar value = liftEff <<< AVar.tryPutVar value

-- | Reads the AVar value. Unlike `takeVar`, this will not leave the AVar empty.
-- | If the AVar is empty, this will queue until it is filled. Multiple reads
@@ -77,5 +92,5 @@ tryReadVar = liftEff <<< AVar.tryReadVar

-- | Kills the AVar with an exception. All pending and future actions will
-- | resolve immediately with the provided exception.
killVar eff a. AVar a Error Aff (avar AVAR | eff) Unit
killVar avar = liftEff <<< AVar.killVar avar
killVar eff a. Error AVar a Aff (avar AVAR | eff) Unit
killVar error = liftEff <<< AVar.killVar error
2 changes: 1 addition & 1 deletion test/Test/Main.purs
Original file line number Diff line number Diff line change
@@ -556,7 +556,7 @@ test_avar_order = assert "avar/order" do
delay (Milliseconds 10.0)
value ← takeVar var
modifyRef ref (_ <> value)
putVar var "foo"
putVar "foo" var
modifyRef ref (_ <> "taken")
joinFiber f1
eq "takenfoo" <$> readRef ref

0 comments on commit 46749af

Please sign in to comment.