Skip to content

Commit 02daa5c

Browse files
committed
Add resumable widgets as a pattern
1 parent 733d283 commit 02daa5c

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
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: 55 additions & 2 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, ($), (<<<), (>>>))
13+
import Data.Foldable (fold)
14+
import Data.Function (applyFlipped, flip, (#), ($), (<<<), (>>>))
1215
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,50 @@ 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+
, view :: Ref v
166+
, canceler :: Effect Unit
167+
}
168+
169+
resumeResumable :: forall v a. ResumableWidget v a -> Widget v a
170+
resumeResumable { handlerRef, view, canceler } = mkWidget \cb -> do
171+
Ref.write cb handlerRef
172+
v <- Ref.read view
173+
cb (View v)
174+
pure canceler
175+
176+
suspendResumable :: forall v a. ResumableWidget v a -> Effect Unit
177+
suspendResumable { handlerRef } = Ref.write mempty handlerRef
178+
179+
cancelResumable :: forall v a. ResumableWidget v a -> Effect Unit
180+
cancelResumable { canceler } = canceler
181+
182+
runToResumable :: forall v a. Widget v a -> Ref v -> (Result v a -> Effect Unit) -> Effect (ResumableWidget v a)
183+
runToResumable w view handler = do
184+
handlerRef <- Ref.new handler
185+
canceler <- runWidget w \res -> Ref.read handlerRef >>= applyFlipped res
186+
pure { handlerRef, view, canceler }
187+
188+
resumableOrr :: forall v a. Monoid v => Array (Widget v a) -> Widget v { val :: a, others :: Array (ResumableWidget v a) }
189+
resumableOrr widgets = mkWidget \cb -> do
190+
viewsRef <- Ref.new (Array.replicate (Array.length widgets) mempty)
191+
resumables <- fixEffect \resumables -> forWithIndex widgets \i w -> do
192+
viewRef <- Ref.new mempty
193+
fixEffect \s -> runToResumable w viewRef case _ of
194+
View v -> do
195+
Ref.write v viewRef
196+
views <- Ref.read viewsRef
197+
Array.updateAt i v views # traverse_ \newViews -> do
198+
Ref.write newViews viewsRef
199+
cb (View (fold newViews))
200+
Completed val -> do
201+
cancelResumable (s unit)
202+
let others = fromMaybe (resumables unit) $ Array.deleteAt i (resumables unit)
203+
traverse_ suspendResumable others
204+
cb (Completed { val, others })
205+
pure do traverse_ cancelResumable resumables
206+

0 commit comments

Comments
 (0)