Skip to content

Commit 47c1af4

Browse files
committed
Add resumable widgets as a pattern
1 parent 733d283 commit 47c1af4

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ html/index.js
1515
.cache
1616
dist
1717
/.psc-ide-port
18+
.devenv
19+
.devenv.flake.nix

src/Concur/Core/Patterns.purs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
module Concur.Core.Patterns where
22

33
import Concur.Core (Result(..), Widget, mkWidget)
4+
import Concur.Core.Types (runWidget)
45
import Control.Alt (class Alt, (<|>))
56
import Control.Applicative (pure)
67
import Control.Bind (bind, discard, (>>=))
78
import Control.Monad (class Monad)
9+
import Control.MonadFix (fixEffect)
810
import Control.Plus (class Plus)
911
import Data.Array as Array
1012
import Data.Either (Either(..), either)
11-
import Data.Function (flip, ($), (<<<), (>>>))
12-
import Data.Functor ((<$>))
13+
import Data.Foldable (fold)
14+
import Data.Function (applyFlipped, flip, (#), ($), (<<<), (>>>))
15+
import Data.Functor ((<$>), ($>))
1316
import Data.Lens (Lens')
1417
import Data.Lens as L
15-
import Data.Monoid (class Monoid)
18+
import Data.Maybe (fromMaybe)
19+
import Data.Monoid (class Monoid, mempty)
1620
import Data.Newtype (class Newtype, un)
1721
import Data.Semigroup ((<>))
1822
import Data.Traversable (traverse_)
23+
import Data.TraversableWithIndex (forWithIndex)
1924
import Data.Unit (Unit, unit)
2025
import Effect (Effect)
2126
import Effect.Class (class MonadEffect, liftEffect)
27+
import Effect.Ref (Ref)
2228
import Effect.Ref as Ref
2329
import Unsafe.Reference (unsafeRefEq)
2430

@@ -151,3 +157,42 @@ with wire f = do
151157
res <- (Left <$> f a) <|> (Right <$> receive wire)
152158
either pure go res
153159

160+
---
161+
-- RESUMABLE WIDGETS (WIP)
162+
163+
type ResumableWidget v a =
164+
{ handlerRef :: Ref (Result v a -> Effect Unit)
165+
, canceler :: Effect Unit
166+
}
167+
168+
resumeResumable :: forall v a. ResumableWidget v a -> Widget v a
169+
resumeResumable { handlerRef, canceler } = mkWidget \cb -> Ref.write cb handlerRef $> canceler
170+
171+
suspendResumable :: forall v a. ResumableWidget v a -> Effect Unit
172+
suspendResumable { handlerRef } = Ref.write mempty handlerRef
173+
174+
cancelResumable :: forall v a. ResumableWidget v a -> Effect Unit
175+
cancelResumable { canceler } = canceler
176+
177+
runResumable :: forall v a. Widget v a -> (Result v a -> Effect Unit) -> Effect (ResumableWidget v a)
178+
runResumable w handler = do
179+
handlerRef <- Ref.new handler
180+
canceler <- runWidget w \res -> Ref.read handlerRef >>= applyFlipped res
181+
pure { handlerRef, canceler }
182+
183+
resumableOrr :: forall v a. Monoid v => Array (Widget v a) -> Widget v { val :: a, others :: Array (ResumableWidget v a) }
184+
resumableOrr widgets = mkWidget \cb -> do
185+
viewsRef <- Ref.new (Array.replicate (Array.length widgets) mempty)
186+
resumables <- fixEffect \resumables -> forWithIndex widgets \i w -> do
187+
fixEffect \s -> runResumable w case _ of
188+
View v -> do
189+
views <- Ref.read viewsRef
190+
Array.updateAt i v views # traverse_ \newViews -> do
191+
Ref.write newViews viewsRef
192+
cb (View (fold newViews))
193+
Completed val -> do
194+
cancelResumable (s unit)
195+
let others = fromMaybe (resumables unit) $ Array.deleteAt i (resumables unit)
196+
traverse_ suspendResumable others
197+
cb (Completed { val, others })
198+
pure do traverse_ _.canceler resumables

0 commit comments

Comments
 (0)