Skip to content

Commit b0a59b5

Browse files
garybnatefaubion
authored andcommitted
Add peekVar for reading from an avar without consuming (#68)
1 parent d27712c commit b0a59b5

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

src/Control/Monad/Aff/AVar.purs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Control.Monad.Aff.AVar
55
, makeVar
66
, makeVar'
77
, takeVar
8+
, peekVar
89
, putVar
910
, modifyVar
1011
, killVar
@@ -15,7 +16,7 @@ import Prelude
1516

1617
import Control.Monad.Aff (Aff, nonCanceler)
1718
import Control.Monad.Aff.Internal (AVar) as Exports
18-
import Control.Monad.Aff.Internal (AVBox, AVar, _killVar, _putVar, _takeVar, _makeVar)
19+
import Control.Monad.Aff.Internal (AVBox, AVar, _killVar, _putVar, _takeVar, _peekVar, _makeVar)
1920
import Control.Monad.Eff.Exception (Error())
2021

2122
import Data.Function.Uncurried (runFn3, runFn2)
@@ -41,6 +42,10 @@ makeVar' a = do
4142
takeVar :: forall e a. AVar a -> AffAVar e a
4243
takeVar q = fromAVBox $ runFn2 _takeVar nonCanceler q
4344

45+
-- | Reads a value from the asynchronous var but does not consume it.
46+
peekVar :: forall e a. AVar a -> AffAVar e a
47+
peekVar q = fromAVBox $ runFn2 _peekVar nonCanceler q
48+
4449
-- | Puts a new value into the asynchronous avar. If the avar has
4550
-- | been killed, this will result in an error.
4651
putVar :: forall e a. AVar a -> a -> AffAVar e Unit

src/Control/Monad/Aff/Internal.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ exports._takeVar = function (nonCanceler, avar) {
3333
};
3434
};
3535

36+
exports._peekVar = function (nonCanceler, avar) {
37+
return function(success, error) {
38+
if (avar.error !== undefined) {
39+
error(avar.error);
40+
} else if (avar.producers.length > 0) {
41+
var producer = avar.producers[0];
42+
producer(success, error);
43+
} else {
44+
avar.consumers.push({peek: true, success: success, error: error});
45+
}
46+
return nonCanceler;
47+
};
48+
};
49+
3650
exports._putVar = function (nonCanceler, avar, a) {
3751
return function(success, error) {
3852
if (avar.error !== undefined) {
@@ -48,15 +62,17 @@ exports._putVar = function (nonCanceler, avar, a) {
4862

4963
success({});
5064
} else {
51-
var consumer = avar.consumers.shift();
5265

53-
try {
54-
consumer.success(a);
55-
} catch (err) {
56-
error(err);
57-
58-
return;
59-
}
66+
var consumer;
67+
do {
68+
consumer = avar.consumers.shift();
69+
try {
70+
consumer.success(a);
71+
} catch (err) {
72+
error(err);
73+
return;
74+
}
75+
} while (consumer.peek === true);
6076

6177
success({});
6278
}

src/Control/Monad/Aff/Internal.purs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Control.Monad.Aff.Internal
33
, AVar
44
, _makeVar
55
, _takeVar
6+
, _peekVar
67
, _putVar
78
, _killVar
89
) where
@@ -21,6 +22,8 @@ foreign import _makeVar :: forall c a. c -> AVBox (AVar a)
2122

2223
foreign import _takeVar :: forall c a. Fn2 c (AVar a) (AVBox a)
2324

25+
foreign import _peekVar :: forall c a. Fn2 c (AVar a) (AVBox a)
26+
2427
foreign import _putVar :: forall c a. Fn3 c (AVar a) a (AVBox Unit)
2528

2629
foreign import _killVar :: forall c a. Fn3 c (AVar a) Error (AVBox Unit)

test/Test/Main.purs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Control.Alt ((<|>))
66
import Control.Apply ((*>))
77
import Control.Parallel.Class (parallel, runParallel)
88
import Control.Monad.Aff (Aff, runAff, makeAff, launchAff, later, later', forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize)
9-
import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, killVar)
9+
import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, peekVar, killVar)
1010
import Control.Monad.Aff.Console (CONSOLE, log)
1111
import Control.Monad.Cont.Class (callCC)
1212
import Control.Monad.Eff (Eff)
@@ -69,6 +69,23 @@ test_putTakeVar = do
6969
a <- takeVar v
7070
log ("Success: Value " <> show a)
7171

72+
test_peekVar :: TestAVar Unit
73+
test_peekVar = do
74+
v <- makeVar
75+
forkAff (later $ putVar v 1.0)
76+
a1 <- peekVar v
77+
a2 <- takeVar v
78+
when (a1 /= a2) do
79+
throwError (error "Something horrible went wrong - peeked var is not equal to taken var")
80+
log ("Success: Peeked value not consumed")
81+
82+
w <- makeVar
83+
putVar w true
84+
b <- peekVar w
85+
when (not b) do
86+
throwError (error "Something horrible went wrong - peeked var is not true")
87+
log ("Success: Peeked value read from written var")
88+
7289
test_killFirstForked :: Test Unit
7390
test_killFirstForked = do
7491
c <- forkAff (later' 100 $ pure "Failure: This should have been killed!")
@@ -237,6 +254,9 @@ main = do
237254
log "Testing AVar - putVar, takeVar"
238255
test_putTakeVar
239256

257+
log "Testing AVar - peekVar"
258+
test_peekVar
259+
240260
log "Testing AVar killVar"
241261
test_killVar
242262

0 commit comments

Comments
 (0)