Skip to content

Commit 2943766

Browse files
authored
Merge pull request #98 from syaiful6/avar-op
add tryTakeVar and tryPeekVar
2 parents 1485978 + 5305e0a commit 2943766

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

src/Control/Monad/Aff/AVar.purs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ module Control.Monad.Aff.AVar
99
, putVar
1010
, modifyVar
1111
, killVar
12+
, tryTakeVar
13+
, tryPeekVar
1214
, module Exports
1315
) where
1416

1517
import Prelude
1618

1719
import Control.Monad.Aff (Aff, nonCanceler)
1820
import Control.Monad.Aff.Internal (AVar) as Exports
19-
import Control.Monad.Aff.Internal (AVBox, AVar, _killVar, _putVar, _takeVar, _peekVar, _makeVar)
21+
import Control.Monad.Aff.Internal (AVBox, AVar, _killVar, _putVar, _takeVar, _peekVar, _makeVar, _tryTakeVar, _tryPeekVar)
2022
import Control.Monad.Eff (kind Effect)
2123
import Control.Monad.Eff.Exception (Error())
2224

23-
import Data.Function.Uncurried (runFn3, runFn2)
25+
import Data.Function.Uncurried (runFn4, runFn3, runFn2)
26+
import Data.Maybe (Maybe(..))
2427

2528
import Unsafe.Coerce (unsafeCoerce)
2629

@@ -43,10 +46,20 @@ makeVar' a = do
4346
takeVar :: forall e a. AVar a -> AffAVar e a
4447
takeVar q = fromAVBox $ runFn2 _takeVar nonCanceler q
4548

49+
-- | A variant of `takeVar` which return immediately if the asynchronous avar
50+
-- | was empty. Nothing if the avar empty and `Just a` if the avar have contents `a`.
51+
tryTakeVar :: forall e a. AVar a -> AffAVar e (Maybe a)
52+
tryTakeVar q = fromAVBox $ runFn4 _tryTakeVar Nothing Just nonCanceler q
53+
4654
-- | Reads a value from the asynchronous var but does not consume it.
4755
peekVar :: forall e a. AVar a -> AffAVar e a
4856
peekVar q = fromAVBox $ runFn2 _peekVar nonCanceler q
4957

58+
-- | A variant of `peekVar` which return immediately when the asynchronous avar
59+
-- | was empty. Nothing if the avar empty and `Just a` if the avar have contents `a`.
60+
tryPeekVar :: forall e a. AVar a -> AffAVar e (Maybe a)
61+
tryPeekVar q = fromAVBox $ runFn4 _tryPeekVar Nothing Just nonCanceler q
62+
5063
-- | Puts a new value into the asynchronous avar. If the avar has
5164
-- | been killed, this will result in an error.
5265
putVar :: forall e a. AVar a -> a -> AffAVar e Unit

src/Control/Monad/Aff/Internal.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ exports._takeVar = function (nonCanceler, avar) {
2525
};
2626
};
2727

28+
exports._tryTakeVar = function (nothing, just, nonCanceler, avar) {
29+
return function (success, error) {
30+
if (avar.error !== undefined) {
31+
error(avar.error);
32+
} else if (avar.producers.length > 0) {
33+
avar.producers.shift()(function (x) {
34+
return success(just(x));
35+
}, error);
36+
} else {
37+
success(nothing);
38+
}
39+
return nonCanceler;
40+
};
41+
};
42+
2843
exports._peekVar = function (nonCanceler, avar) {
2944
return function (success, error) {
3045
if (avar.error !== undefined) {
@@ -38,6 +53,21 @@ exports._peekVar = function (nonCanceler, avar) {
3853
};
3954
};
4055

56+
exports._tryPeekVar = function (nothing, just, nonCanceler, avar) {
57+
return function (success, error) {
58+
if (avar.error !== undefined) {
59+
error(avar.error);
60+
} else if (avar.producers.length > 0) {
61+
avar.producers[0](function (x) {
62+
return success(just(x));
63+
}, error);
64+
} else {
65+
success(nothing);
66+
}
67+
return nonCanceler;
68+
};
69+
};
70+
4171
exports._putVar = function (nonCanceler, avar, a) {
4272
return function (success, error) {
4373
if (avar.error !== undefined) {

src/Control/Monad/Aff/Internal.purs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module Control.Monad.Aff.Internal
33
, AVar
44
, _makeVar
55
, _takeVar
6+
, _tryTakeVar
67
, _peekVar
8+
, _tryPeekVar
79
, _putVar
810
, _killVar
911
) where
@@ -12,7 +14,8 @@ import Prelude
1214

1315
import Control.Monad.Eff.Exception (Error)
1416

15-
import Data.Function.Uncurried (Fn2, Fn3)
17+
import Data.Maybe (Maybe)
18+
import Data.Function.Uncurried (Fn2, Fn3, Fn4)
1619

1720
foreign import data AVar :: Type -> Type
1821

@@ -22,8 +25,12 @@ foreign import _makeVar :: forall c a. c -> AVBox (AVar a)
2225

2326
foreign import _takeVar :: forall c a. Fn2 c (AVar a) (AVBox a)
2427

28+
foreign import _tryTakeVar :: forall c a. Fn4 (forall x. Maybe x) (forall x. x -> Maybe x) c (AVar a) (AVBox (Maybe a))
29+
2530
foreign import _peekVar :: forall c a. Fn2 c (AVar a) (AVBox a)
2631

32+
foreign import _tryPeekVar :: forall c a. Fn4 (forall x. Maybe x) (forall x. x -> Maybe x) c (AVar a) (AVBox (Maybe a))
33+
2734
foreign import _putVar :: forall c a. Fn3 c (AVar a) a (AVBox Unit)
2835

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

test/Test/Main.purs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Prelude
44

55
import Control.Alt ((<|>))
66
import Control.Monad.Aff (Aff, runAff, makeAff, launchAff, delay, forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize)
7-
import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, peekVar, killVar)
7+
import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, peekVar, killVar, tryTakeVar, tryPeekVar)
88
import Control.Monad.Aff.Console (CONSOLE, log)
99
import Control.Monad.Eff (Eff)
1010
import Control.Monad.Eff.Console (log) as Eff
@@ -129,6 +129,42 @@ test_killVar = do
129129
e <- attempt $ takeVar v
130130
either (const $ log "Success: Killed queue dead") (const $ log "Failure: Oh noes, queue survived!") e
131131

132+
test_tryTakeVar :: TestAVar Unit
133+
test_tryTakeVar = do
134+
timeout (Milliseconds 1000.0) do
135+
v <- makeVar
136+
x <- tryTakeVar v
137+
case x of
138+
Nothing -> log $ "Success: trying take an empty var"
139+
Just _ -> throwError $ error $ "Failure: Oh noes, take an empty var should return Nothing"
140+
141+
timeout (Milliseconds 1000.0) do
142+
v <- makeVar
143+
b <- tryTakeVar v
144+
putVar v 1.0
145+
a <- tryTakeVar v
146+
when (a /= Just 1.0 || a == b) do
147+
throwError $ error ("Failure: Oh noes, tryTakeVar should take var if it available, value: " <> show a)
148+
log $ "Success: value taken by tryTakeVar " <> show a
149+
150+
test_tryPeekVar :: TestAVar Unit
151+
test_tryPeekVar = do
152+
timeout (Milliseconds 1000.0) do
153+
v <- makeVar
154+
x <- tryPeekVar v
155+
case x of
156+
Nothing -> log $ "Success: try peek var return immediately"
157+
Just _ -> throwError $ error $ "Failure: tryPeekVar return Just when peek an empty var"
158+
159+
timeout (Milliseconds 1000.0) do
160+
v <- makeVar
161+
putVar v 100.0
162+
a <- tryPeekVar v
163+
b <- takeVar v
164+
when (a /= Just b) do
165+
throwError (error "Something horrible went wrong - peeked var is not equal to taken var")
166+
log ("Success: Try Peeked value not consumed")
167+
132168
test_finally :: TestAVar Unit
133169
test_finally = do
134170
v <- makeVar
@@ -311,6 +347,12 @@ main = do
311347
log "Testing AVar killVar"
312348
test_killVar
313349

350+
log "Testing AVar - tryTakeVar"
351+
test_tryTakeVar
352+
353+
log "Testing AVar - tryPeekVar"
354+
test_tryPeekVar
355+
314356
log "Testing finally"
315357
test_finally
316358

0 commit comments

Comments
 (0)