{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE RecursiveDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
#ifdef USE_REFLEX_OPTIMIZER
{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
#endif
module Reflex.Requester.Base
( RequesterT (..)
, runRequesterT
, withRequesterT
, runWithReplaceRequesterTWith
, traverseIntMapWithKeyWithAdjustRequesterTWith
, traverseDMapWithKeyWithAdjustRequesterTWith
, RequesterData
, RequesterDataKey
, traverseRequesterData
, forRequesterData
, requesterDataToList
, singletonRequesterData
, matchResponsesWithRequests
, matchResponseMapWithRequests
, multiEntry
, unMultiEntry
, requesting'
) where
import Reflex.Class
import Reflex.Adjustable.Class
import Reflex.Dynamic
import Reflex.Host.Class
import Reflex.PerformEvent.Class
import Reflex.PostBuild.Class
import Reflex.Requester.Class
import Reflex.TriggerEvent.Class
import Control.Applicative (liftA2)
import Control.Monad.Exception
import Control.Monad.Identity
import Control.Monad.Morph
import Control.Monad.Primitive
import Control.Monad.Reader
import Control.Monad.Ref
import Control.Monad.State.Strict
import Data.Bits
import Data.Coerce
import Data.Constraint
import Data.Dependent.Map (DMap)
import qualified Data.Dependent.Map as DMap
import Data.Dependent.Sum (DSum (..))
import Data.Functor.Compose
import Data.Functor.Misc
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IntMap
import Data.Kind (Type)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Monoid ((<>))
import Data.Proxy
import qualified Data.Semigroup as S
import Data.Some (Some(Some))
import Data.Type.Equality
import Data.Unique.Tag
import GHC.Exts (Any)
import Unsafe.Coerce
newtype TagMap (f :: Type -> Type) = TagMap (IntMap Any)
newtype RequesterData f = RequesterData (TagMap (Entry f))
emptyRequesterData :: RequesterData f
emptyRequesterData = RequesterData $ TagMap IntMap.empty
data RequesterDataKey a where
RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
RequesterDataKey_Multi2 :: GCompare k => {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
singletonRequesterData rdk v = case rdk of
RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Multi2Contents
{ _multi2Contents_values = Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
, _multi2Contents_dict = Dict
}
RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
mergeRequesterData :: RequesterData f -> RequesterData f -> RequesterData f
mergeRequesterData (RequesterData a) (RequesterData b) = RequesterData $ mergeTagMap a b
mergeTagMap :: forall f. TagMap (Entry f) -> TagMap (Entry f) -> TagMap (Entry f)
mergeTagMap (TagMap m) (TagMap n) =
TagMap $ IntMap.unionWithKey (g' combiner) m n
where
combiner :: forall a. MyTag a -> Entry f a -> Entry f a -> Entry f a
combiner k (Entry a) (Entry b) = Entry $ case myKeyType k of
MyTagType_Single -> a
MyTagType_Multi -> IntMap.unionWith mergeRequesterData a b
MyTagType_Multi2 -> case _multi2Contents_dict a of
Dict -> Multi2Contents
{ _multi2Contents_values = Map.unionWith (IntMap.unionWith mergeRequesterData) (_multi2Contents_values a) (_multi2Contents_values b)
, _multi2Contents_dict = Dict
}
MyTagType_Multi3 -> IntMap.unionWith (IntMap.unionWith mergeRequesterData) a b
g' :: (forall a. MyTag a -> Entry f a -> Entry f a -> Entry f a) -> Int -> Any -> Any -> Any
g' f rawKey a b =
let k = MyTag rawKey :: MyTag a
fromAny :: Any -> Entry f a
fromAny = unsafeCoerce
toAny :: Entry f a -> Any
toAny = unsafeCoerce
in toAny $ f k (fromAny a) (fromAny b)
requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
requesterDataToList (RequesterData m) = do
k :=> Entry e <- tagMapToList m
case myKeyType k of
MyTagType_Single -> return $ RequesterDataKey_Single k :=> e
MyTagType_Multi -> do
(k', e') <- IntMap.toList e
k'' :=> e'' <- requesterDataToList e'
return $ RequesterDataKey_Multi k k' k'' :=> e''
MyTagType_Multi2 -> case _multi2Contents_dict e of
Dict -> do
(k', e') <- Map.toList $ _multi2Contents_values e
(k'', e'') <- IntMap.toList e'
k''' :=> e''' <- requesterDataToList e''
return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
MyTagType_Multi3 -> do
(k', e') <- IntMap.toList e
(k'', e'') <- IntMap.toList e'
k''' :=> e''' <- requesterDataToList e''
return $ RequesterDataKey_Multi3 k k' k'' k''' :=> e'''
singletonTagMap :: forall f a. MyTag a -> f a -> TagMap f
singletonTagMap (MyTag k) v = TagMap $ IntMap.singleton k $ (unsafeCoerce :: f a -> Any) v
tagMapToList :: forall f. TagMap f -> [DSum MyTag f]
tagMapToList (TagMap m) = f <$> IntMap.toList m
where f :: (Int, Any) -> DSum MyTag f
f (k, v) = MyTag k :=> (unsafeCoerce :: Any -> f a) v
traverseTagMapWithKey :: forall t f g. Applicative t => (forall a. MyTag a -> f a -> t (g a)) -> TagMap f -> t (TagMap g)
traverseTagMapWithKey f (TagMap m) = TagMap <$> IntMap.traverseWithKey g m
where
g :: Int -> Any -> t Any
g k v = (unsafeCoerce :: g a -> Any) <$> f (MyTag k) ((unsafeCoerce :: Any -> f a) v)
traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequesterData request -> m (RequesterData response)
traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWithKey go m
where go :: forall x. MyTag x -> Entry request x -> m (Entry response x)
go k (Entry request) = Entry <$> case myKeyType k of
MyTagType_Single -> f request
MyTagType_Multi -> traverse (traverseRequesterData f) request
MyTagType_Multi2 -> case request of
Multi2Contents { _multi2Contents_values = request', _multi2Contents_dict = Dict } -> do
v <- traverse (traverse (traverseRequesterData f)) request'
pure $ Multi2Contents
{ _multi2Contents_values = v
, _multi2Contents_dict = Dict
}
MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
forRequesterData :: forall request response m. Applicative m => RequesterData request -> (forall a. request a -> m (response a)) -> m (RequesterData response)
forRequesterData r f = traverseRequesterData f r
data MyTagType :: Type -> Type where
MyTagType_Single :: MyTagType (Single a)
MyTagType_Multi :: MyTagType Multi
MyTagType_Multi2 :: MyTagType (Multi2 k)
MyTagType_Multi3 :: MyTagType Multi3
myKeyType :: MyTag x -> MyTagType x
myKeyType (MyTag k) = case k .&. 0x3 of
0x0 -> unsafeCoerce MyTagType_Single
0x1 -> unsafeCoerce MyTagType_Multi
0x2 -> unsafeCoerce MyTagType_Multi2
0x3 -> unsafeCoerce MyTagType_Multi3
t -> error $ "Reflex.Requester.Base.myKeyType: no such key type" <> show t
data Single a
data Multi
data Multi2 (k :: Type -> Type)
data Multi3
class MyTagTypeOffset x where
myTagTypeOffset :: proxy x -> Int
instance MyTagTypeOffset (Single a) where
myTagTypeOffset _ = 0x0
instance MyTagTypeOffset Multi where
myTagTypeOffset _ = 0x1
instance MyTagTypeOffset (Multi2 k) where
myTagTypeOffset _ = 0x2
instance MyTagTypeOffset Multi3 where
myTagTypeOffset _ = 0x3
type family EntryContents request a where
EntryContents request (Single a) = request a
EntryContents request Multi = IntMap (RequesterData request)
EntryContents request (Multi2 k) = Multi2Contents k request
EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
data Multi2Contents k request = Multi2Contents
{ _multi2Contents_dict :: {-# UNPACK #-} !(Dict (GCompare k))
, _multi2Contents_values :: {-# UNPACK #-} !(Map (Some k) (IntMap (RequesterData request)))
}
newtype Entry request x = Entry { unEntry :: EntryContents request x }
{-# INLINE singleEntry #-}
singleEntry :: f a -> Entry f (Single a)
singleEntry = Entry
{-# INLINE multiEntry #-}
multiEntry :: IntMap (RequesterData f) -> Entry f Multi
multiEntry = Entry
{-# INLINE unMultiEntry #-}
unMultiEntry :: Entry f Multi -> IntMap (RequesterData f)
unMultiEntry = unEntry
newtype MyTag x = MyTag Int deriving (Show, Eq, Ord, Enum)
newtype MyTagWrap (f :: Type -> Type) x = MyTagWrap Int deriving (Show, Eq, Ord, Enum)
{-# INLINE castMyTagWrap #-}
castMyTagWrap :: MyTagWrap f (Entry f x) -> MyTagWrap g (Entry g x)
castMyTagWrap = coerce
instance GEq MyTag where
(MyTag a) `geq` (MyTag b) =
if a == b
then Just $ unsafeCoerce Refl
else Nothing
instance GCompare MyTag where
(MyTag a) `gcompare` (MyTag b) =
case a `compare` b of
LT -> GLT
EQ -> unsafeCoerce GEQ
GT -> GGT
instance GEq (MyTagWrap f) where
(MyTagWrap a) `geq` (MyTagWrap b) =
if a == b
then Just $ unsafeCoerce Refl
else Nothing
instance GCompare (MyTagWrap f) where
(MyTagWrap a) `gcompare` (MyTagWrap b) =
case a `compare` b of
LT -> GLT
EQ -> unsafeCoerce GEQ
GT -> GGT
data RequesterState t (request :: Type -> Type) = RequesterState
{ _requesterState_nextMyTag :: {-# UNPACK #-} !Int
, _requesterState_requests :: ![(Int, Event t Any)]
}
newtype RequesterT t request (response :: Type -> Type) m a = RequesterT { unRequesterT :: StateT (RequesterState t request) (ReaderT (EventSelectorInt t Any) m) a }
deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
#if MIN_VERSION_base(4,9,1)
, MonadAsyncException
#endif
)
deriving instance MonadSample t m => MonadSample t (RequesterT t request response m)
deriving instance MonadHold t m => MonadHold t (RequesterT t request response m)
deriving instance PostBuild t m => PostBuild t (RequesterT t request response m)
deriving instance TriggerEvent t m => TriggerEvent t (RequesterT t request response m)
instance PrimMonad m => PrimMonad (RequesterT t request response m) where
type PrimState (RequesterT t request response m) = PrimState m
primitive = lift . primitive
instance (Monoid a, Monad m) => Monoid (RequesterT t request response m a) where
mempty = pure mempty
mappend = liftA2 mappend
instance (S.Semigroup a, Monad m) => S.Semigroup (RequesterT t request response m a) where
(<>) = liftA2 (S.<>)
runRequesterT :: (Reflex t, Monad m)
=> RequesterT t request response m a
-> Event t (RequesterData response)
-> m (a, Event t (RequesterData request))
runRequesterT (RequesterT a) responses = do
(result, s) <- runReaderT (runStateT a $ RequesterState (-4) []) $ fanInt $
coerceEvent responses
return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
withRequesterT
:: (Reflex t, MonadFix m)
=> (forall x. req x -> req' x)
-> (forall x. rsp' x -> rsp x)
-> RequesterT t req rsp m a
-> RequesterT t req' rsp' m a
withRequesterT freq frsp child = do
rec let rsp = fmap (runIdentity . traverseRequesterData (Identity . frsp)) rsp'
(a, req) <- lift $ runRequesterT child rsp
rsp' <- fmap (flip selectInt 0 . fanInt . fmapCheap unMultiEntry) $ requesting' $
fmapCheap (multiEntry . IntMap.singleton 0) $ fmap (runIdentity . traverseRequesterData (Identity . freq)) req
return a
instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
type Request (RequesterT t request response m) = request
type Response (RequesterT t request response m) = response
requesting = fmap coerceEvent . responseFromTag . castMyTagWrap <=< tagRequest . (coerceEvent :: Event t (request a) -> Event t (Entry request (Single a)))
requesting_ = void . tagRequest . fmapCheap singleEntry
{-# INLINE tagRequest #-}
tagRequest :: forall m x t request response. (Monad m, MyTagTypeOffset x) => Event t (Entry request x) -> RequesterT t request response m (MyTagWrap request (Entry request x))
tagRequest req = do
old <- RequesterT get
let n = _requesterState_nextMyTag old .|. myTagTypeOffset (Proxy :: Proxy x)
t = MyTagWrap n
RequesterT $ put $ RequesterState
{ _requesterState_nextMyTag = _requesterState_nextMyTag old - 0x4
, _requesterState_requests = (n, (unsafeCoerce :: Event t (Entry request x) -> Event t Any) req) : _requesterState_requests old
}
return t
{-# INLINE responseFromTag #-}
responseFromTag :: forall m t request response x. Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
responseFromTag (MyTagWrap t) = do
responses :: EventSelectorInt t Any <- RequesterT ask
return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
instance MonadTrans (RequesterT t request response) where
lift = RequesterT . lift . lift
instance MFunctor (RequesterT t request response) where
hoist f = RequesterT . hoist (hoist f) . unRequesterT
instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
type Performable (RequesterT t request response m) = Performable m
performEvent_ = lift . performEvent_
performEvent = lift . performEvent
instance MonadRef m => MonadRef (RequesterT t request response m) where
type Ref (RequesterT t request response m) = Ref m
newRef = lift . newRef
readRef = lift . readRef
writeRef r = lift . writeRef r
instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
newEventWithTrigger = lift . newEventWithTrigger
newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
instance MonadReader r m => MonadReader r (RequesterT t request response m) where
ask = lift ask
local f (RequesterT a) = RequesterT $ mapStateT (mapReaderT $ local f) a
reader = lift . reader
instance (Reflex t, Adjustable t m, MonadHold t m, MonadFix m) => Adjustable t (RequesterT t request response m) where
runWithReplace = runWithReplaceRequesterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElementsMap mergeIntIncremental
{-# INLINABLE traverseDMapWithKeyWithAdjust #-}
traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental
traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove
requesting' :: (MyTagTypeOffset x, Monad m) => Event t (Entry request x) -> RequesterT t request response m (Event t (Entry response x))
requesting' = responseFromTag . castMyTagWrap <=< tagRequest
{-# INLINABLE runWithReplaceRequesterTWith #-}
runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
, MonadFix m
)
=> (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
-> RequesterT t request response m a
-> Event t (RequesterT t request response m b)
-> RequesterT t request response m (a, Event t b)
runWithReplaceRequesterTWith f a0 a' = do
rec na' <- numberOccurrencesFrom 1 a'
responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requests
let responses' = fanInt responses
((result0, requests0), v') <- f (runRequesterT a0 (selectInt responses' 0)) $ fmapCheap (\(n, a) -> fmap ((,) n) $ runRequesterT a $ selectInt responses' n) na'
requests <- holdDyn (fmapCheap (IntMap.singleton 0) requests0) $ fmapCheap (\(n, (_, reqs)) -> fmapCheap (IntMap.singleton n) reqs) v'
return (result0, fmapCheap (fst . snd) v')
{-# INLINE traverseIntMapWithKeyWithAdjustRequesterTWith #-}
traverseIntMapWithKeyWithAdjustRequesterTWith :: forall t request response m v v' p.
( Reflex t
, MonadHold t m
, PatchTarget (p (Event t (IntMap (RequesterData request)))) ~ IntMap (Event t (IntMap (RequesterData request)))
, Patch (p (Event t (IntMap (RequesterData request))))
, Functor p
, MonadFix m
)
=> ( (IntMap.Key -> (IntMap.Key, v) -> m (Event t (IntMap (RequesterData request)), v'))
-> IntMap (IntMap.Key, v)
-> Event t (p (IntMap.Key, v))
-> RequesterT t request response m (IntMap (Event t (IntMap (RequesterData request)), v'), Event t (p (Event t (IntMap (RequesterData request)), v')))
)
-> (p (Event t (IntMap (RequesterData request))) -> IntMap (Event t (IntMap (RequesterData request))))
-> (Incremental t (p (Event t (IntMap (RequesterData request)))) -> Event t (IntMap (IntMap (RequesterData request))))
-> (IntMap.Key -> v -> RequesterT t request response m v')
-> IntMap v
-> Event t (p v)
-> RequesterT t request response m (IntMap v', Event t (p v'))
traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests
let responses :: EventSelectorInt t (IntMap (RequesterData response))
responses = fanInt $ fmapCheap unpack response
unpack :: Entry response Multi3 -> IntMap (IntMap (RequesterData response))
unpack = unEntry
pack :: IntMap (IntMap (RequesterData request)) -> Entry request Multi3
pack = Entry
f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
f' k (n, v) = do
(result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ selectInt responses k
return (fmapCheap (IntMap.singleton n) myRequests, result)
ndm' <- numberOccurrencesFrom 1 dm'
(children0, children') <- base f' (fmap ((,) 0) dm0) $ fmap (\(n, dm) -> fmap ((,) n) dm) ndm'
let result0 = fmap snd children0
result' = fforCheap children' $ fmap snd
requests0 :: IntMap (Event t (IntMap (RequesterData request)))
requests0 = fmap fst children0
requests' :: Event t (p (Event t (IntMap (RequesterData request))))
requests' = fforCheap children' $ fmap fst
promptRequests :: Event t (IntMap (IntMap (RequesterData request)))
promptRequests = coincidence $ fmapCheap (mergeInt . patchNewElements) requests'
requests <- holdIncremental requests0 requests'
return (result0, result')
{-# INLINE traverseDMapWithKeyWithAdjustRequesterTWith #-}
traverseDMapWithKeyWithAdjustRequesterTWith :: forall k t request response m v v' p p'.
( GCompare k
, Reflex t
, MonadHold t m
, PatchTarget (p' (Some k) (Event t (IntMap (RequesterData request)))) ~ Map (Some k) (Event t (IntMap (RequesterData request)))
, Patch (p' (Some k) (Event t (IntMap (RequesterData request))))
, MonadFix m
)
=> (forall k' v1 v2. GCompare k'
=> (forall a. k' a -> v1 a -> m (v2 a))
-> DMap k' v1
-> Event t (p k' v1)
-> RequesterT t request response m (DMap k' v2, Event t (p k' v2))
)
-> (forall v1 v2. (forall a. v1 a -> v2 a) -> p k v1 -> p k v2)
-> (forall v1 v2. (forall a. v1 a -> v2) -> p k v1 -> p' (Some k) v2)
-> (forall v2. p' (Some k) v2 -> Map (Some k) v2)
-> (forall a. Incremental t (p' (Some k) (Event t a)) -> Event t (Map (Some k) a))
-> (forall a. k a -> v a -> RequesterT t request response m (v' a))
-> DMap k v
-> Event t (p k v)
-> RequesterT t request response m (DMap k v', Event t (p k v'))
traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests
let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
responses = fanMap $ fmapCheap unpack response
unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
unpack = _multi2Contents_values . unEntry
pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
pack m = Entry $ Multi2Contents { _multi2Contents_values = m, _multi2Contents_dict = Dict }
f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
f' k (Compose (n, v)) = do
(result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
ndm' <- numberOccurrencesFrom 1 dm'
(children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
let result0 = DMap.map (snd . getCompose) children0
result' = fforCheap children' $ mapPatch $ snd . getCompose
requests0 :: Map (Some k) (Event t (IntMap (RequesterData request)))
requests0 = weakenDMapWith (fst . getCompose) children0
requests' :: Event t (p' (Some k) (Event t (IntMap (RequesterData request))))
requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
promptRequests :: Event t (Map (Some k) (IntMap (RequesterData request)))
promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests'
requests <- holdIncremental requests0 requests'
return (result0, result')
data Decoder rawResponse response =
forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
matchResponsesWithRequests
:: forall t rawRequest rawResponse request response m.
( MonadFix m
, MonadHold t m
, Reflex t
)
=> (forall a. request a -> (rawRequest, rawResponse -> response a))
-> Event t (RequesterData request)
-> Event t (Int, rawResponse)
-> m ( Event t (Map Int rawRequest)
, Event t (RequesterData response)
)
matchResponsesWithRequests f send recv = matchResponseMapWithRequests f send $ uncurry Map.singleton <$> recv
matchResponseMapWithRequests
:: forall t rawRequest rawResponse request response m.
( MonadFix m
, MonadHold t m
, Reflex t
)
=> (forall a. request a -> (rawRequest, rawResponse -> response a))
-> Event t (RequesterData request)
-> Event t (Map Int rawResponse)
-> m ( Event t (Map Int rawRequest)
, Event t (RequesterData response)
)
matchResponseMapWithRequests f send recv = do
rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
holdIncremental mempty $ leftmost
[ fmap (\(_, outstanding, _) -> outstanding) outgoing
, snd <$> incoming
]
let outgoing = processOutgoing nextId send
incoming = processIncoming waitingFor recv
return (fmap (\(_, _, rawReqs) -> rawReqs) outgoing, fst <$> incoming)
where
processOutgoing
:: Behavior t Int
-> Event t (RequesterData request)
-> Event t ( Int
, PatchMap Int (Decoder rawResponse response)
, Map Int rawRequest )
processOutgoing nextId out = flip pushAlways out $ \dm -> do
oldNextId <- sample nextId
let (result, newNextId) = flip runState oldNextId $ forM (requesterDataToList dm) $ \(k :=> v) -> do
n <- get
put $ succ n
let (rawReq, rspF) = f v
return (n, rawReq, Decoder k rspF)
patchWaitingFor = PatchMap $ Map.fromList $
(\(n, _, dec) -> (n, Just dec)) <$> result
toSend = Map.fromList $ (\(n, rawReq, _) -> (n, rawReq)) <$> result
return (newNextId, patchWaitingFor, toSend)
processIncoming
:: Incremental t (PatchMap Int (Decoder rawResponse response))
-> Event t (Map Int rawResponse)
-> Event t (RequesterData response, PatchMap Int v)
processIncoming waitingFor inc = flip push inc $ \rspMap -> do
wf <- sample $ currentIncremental waitingFor
let match rawRsp (Decoder k rspF) =
let rsp = rspF rawRsp
in singletonRequesterData k rsp
matches = Map.intersectionWith match rspMap wf
pure $ if Map.null matches then Nothing else Just
(Map.foldl' mergeRequesterData emptyRequesterData matches, PatchMap $ Nothing <$ matches)