@@ -0,0 +1,700 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE EmptyDataDecls #-}
4+{-# LANGUAGE ExistentialQuantification #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE GADTs #-}
7+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE Rank2Types #-}
10+{-# LANGUAGE RecursiveDo #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE StandaloneDeriving #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
16+{-# LANGUAGE InstanceSigs #-}
17+#ifdef USE_REFLEX_OPTIMIZER
18+{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
19+#endif
20+module Reflex.Requester.Base.Internal where
21+
22+import Reflex.Class
23+import Reflex.Adjustable.Class
24+import Reflex.Dynamic
25+import Reflex.Host.Class
26+import Reflex.PerformEvent.Class
27+import Reflex.PostBuild.Class
28+import Reflex.Requester.Class
29+import Reflex.TriggerEvent.Class
30+import Reflex.EventWriter.Base
31+import Reflex.EventWriter.Class
32+
33+import Control.Applicative (liftA2)
34+import Control.Monad.Exception
35+import Control.Monad.Identity
36+import Control.Monad.Primitive
37+import Control.Monad.Reader
38+import Control.Monad.Ref
39+import Control.Monad.State.Strict
40+import Data.Bits
41+import Data.Coerce
42+import Data.Dependent.Map (DMap, DSum (..))
43+import qualified Data.Dependent.Map as DMap
44+import Data.Functor.Compose
45+import Data.Functor.Misc
46+import Data.IntMap.Strict (IntMap)
47+import qualified Data.IntMap.Strict as IntMap
48+import qualified Data.List.NonEmpty as NonEmpty
49+import Data.List.NonEmpty.Deferred (NonEmptyDeferred)
50+import qualified Data.List.NonEmpty.Deferred as NonEmptyDeferred
51+import Data.Map (Map)
52+import qualified Data.Map as Map
53+import Data.Monoid ((<>))
54+import Data.Proxy
55+import qualified Data.Semigroup as S
56+import Data.Some (Some(Some))
57+import Data.Type.Equality
58+import Data.Sequence (Seq)
59+import qualified Data.Sequence as Seq
60+import Data.TagMap (TagMap)
61+import qualified Data.TagMap as TagMap
62+import Reflex.FanTag
63+import Data.Unique.Tag.Local
64+import qualified Data.Unique.Tag as Global
65+import Data.GADT.Compare
66+import Data.Witherable
67+import Data.Foldable
68+
69+import Debug.Trace
70+
71+data RequestData ps request = forall s. RequestData !(TagGen ps s) !(NonEmptyDeferred (RequestEnvelope s request))
72+data ResponseData ps response = forall s. ResponseData !(TagGen ps s) !(TagMap s response)
73+
74+traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequestData (PrimState m) request -> m (ResponseData (PrimState m) response)
75+traverseRequesterData f (RequestData tg es) = ResponseData tg . TagMap.fromList <$> wither g (NonEmpty.toList $ NonEmptyDeferred.toNonEmpty es)
76+ where g (RequestEnvelope mt req) = case mt of
77+ Just t -> Just . (t :=>) <$> f req
78+ Nothing -> Nothing <$ f req
79+
80+runRequesterT :: forall t request response m a
81+ . ( Reflex t
82+ , PrimMonad m
83+ , MonadFix m
84+ )
85+ => RequesterT t request response m a
86+ -> Event t (ResponseData (PrimState m) response)
87+ -> m (a, Event t (RequestData (PrimState m) request))
88+runRequesterT (RequesterT a) wrappedResponses = withRequesterInternalT $ \(requests :: Event t (NonEmptyDeferred (RequestEnvelope s request))) -> do
89+ (_, tg) <- RequesterInternalT ask
90+ result <- a
91+ let responses = fforMaybe wrappedResponses $ \(ResponseData tg' m) -> case tg `geq` tg' of
92+ Nothing -> trace ("runRequesterT: bad TagGen: expected " <> show tg <> " but got " <> show tg') Nothing --TODO: Warn somehow
93+ Just Refl -> Just m
94+ pure (responses, (result, fmapCheap (RequestData tg) requests))
95+
96+instance MonadTrans (RequesterInternalT s t request response) where
97+ lift = RequesterInternalT . lift . lift
98+
99+instance MonadTrans (RequesterT t request response) where
100+ lift a = RequesterT $ RequesterInternalT $ lift $ lift a
101+
102+-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
103+-- requests are made, and responses should be provided in the input 'Event'.
104+-- The 'Tag' keys will be used to return the responses to the same place the
105+-- requests were issued.
106+withRequesterInternalT
107+ :: ( Reflex t
108+ , PrimMonad m
109+ , MonadFix m
110+ )
111+ => (forall s. Event t (NonEmptyDeferred (RequestEnvelope s request)) -> RequesterInternalT s t request response m (Event t (TagMap s response), a))
112+ -> m a
113+withRequesterInternalT f = withTagGen $ \tg -> do
114+ rec let RequesterInternalT a = f requests
115+ ((responses, result), requests) <- runEventWriterT $ runReaderT a (fanTag responses, tg)
116+ pure result
117+
118+data RequestEnvelope s request = forall a. RequestEnvelope {-# UNPACK #-} !(Maybe (Tag s a)) !(request a)
119+
120+newtype RequesterT t (request :: * -> *) (response :: * -> *) m a = RequesterT { unRequesterT :: forall s. RequesterInternalT s t request response m a }
121+
122+instance Functor m => Functor (RequesterT t request response m) where
123+ fmap f (RequesterT x) = RequesterT $ fmap f x
124+
125+instance Monad m => Applicative (RequesterT t request response m) where
126+ pure x = RequesterT $ pure x
127+ RequesterT f <*> RequesterT x = RequesterT $ f <*> x
128+ liftA2 f (RequesterT a) (RequesterT b) = RequesterT $ liftA2 f a b
129+ RequesterT f <* RequesterT x = RequesterT $ f <* x
130+ RequesterT f *> RequesterT x = RequesterT $ f *> x
131+
132+instance Monad m => Monad (RequesterT t request response m) where
133+ return = pure
134+ RequesterT mx >>= f = RequesterT $ mx >>= \x -> case f x of
135+ RequesterT y -> y
136+
137+instance MonadFix m => MonadFix (RequesterT t request response m) where
138+ mfix f = RequesterT $ mfix $ \x -> case f x of
139+ RequesterT a -> a
140+
141+instance MonadIO m => MonadIO (RequesterT t request respnose m) where
142+ liftIO a = RequesterT $ liftIO a
143+
144+instance MonadException m => MonadException (RequesterT t request respnose m) where
145+ throw e = RequesterT $ throw e
146+
147+newtype RequesterInternalT s t request response m a = RequesterInternalT { unRequesterInternalT :: ReaderT (EventSelectorTag t s response, TagGen (PrimState m) s) (EventWriterT t (NonEmptyDeferred (RequestEnvelope s request)) m) a }
148+ deriving
149+ ( Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
150+#if MIN_VERSION_base(4,9,1)
151+ , MonadAsyncException
152+#endif
153+ )
154+
155+-- I don't think this can actually be supported without an unsafeCoerce
156+-- #if MIN_VERSION_base(4,9,1)
157+-- instance MonadAsyncException m => MonadAsyncException (RequesterT t request response m) where
158+-- mask f = RequesterT $ mask $ \unmask -> unRequesterT $ f $ \x -> RequesterT $ unmask $ unRequesterT x
159+-- #endif
160+
161+instance MonadSample t m => MonadSample t (RequesterT t request response m)
162+instance MonadHold t m => MonadHold t (RequesterT t request response m)
163+instance PostBuild t m => PostBuild t (RequesterT t request response m)
164+instance TriggerEvent t m => TriggerEvent t (RequesterT t request response m)
165+
166+instance MonadSample t m => MonadSample t (RequesterInternalT s t request response m)
167+instance MonadHold t m => MonadHold t (RequesterInternalT s t request response m)
168+instance PostBuild t m => PostBuild t (RequesterInternalT s t request response m)
169+instance TriggerEvent t m => TriggerEvent t (RequesterInternalT s t request response m)
170+
171+instance PrimMonad m => PrimMonad (RequesterT t request response m) where
172+ type PrimState (RequesterT t request response m) = PrimState m
173+ primitive = lift . primitive
174+
175+-- TODO: Monoid and Semigroup can likely be derived once StateT has them.
176+instance (Monoid a, Monad m) => Monoid (RequesterT t request response m a) where
177+ mempty = pure mempty
178+ mappend = liftA2 mappend
179+
180+instance (S.Semigroup a, Monad m) => S.Semigroup (RequesterT t request response m a) where
181+ (<>) = liftA2 (S.<>)
182+
183+instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
184+ type Performable (RequesterT t request response m) = Performable m
185+ performEvent_ = lift . performEvent_
186+ performEvent = lift . performEvent
187+
188+instance MonadRef m => MonadRef (RequesterT t request response m) where
189+ type Ref (RequesterT t request response m) = Ref m
190+ newRef = lift . newRef
191+ readRef = lift . readRef
192+ writeRef r = lift . writeRef r
193+
194+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
195+ newEventWithTrigger = lift . newEventWithTrigger
196+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
197+
198+instance MonadReader r m => MonadReader r (RequesterT t request response m) where
199+ ask = lift ask
200+ local f (RequesterT a) = RequesterT $ RequesterInternalT $ mapReaderT (mapEventWriterT $ local f) $ unRequesterInternalT a
201+ reader = lift . reader
202+
203+instance (Reflex t, PrimMonad m) => Requester t (RequesterT t request response m) where
204+ type Request (RequesterT t request response m) = request
205+ type Response (RequesterT t request response m) = response
206+ requesting e = RequesterT $ requesting e
207+ requesting_ e = RequesterT $ requesting_ e
208+
209+instance (Reflex t, PrimMonad m) => Requester t (RequesterInternalT s t request response m) where
210+ type Request (RequesterInternalT s t request response m) = request
211+ type Response (RequesterInternalT s t request response m) = response
212+ requesting e = RequesterInternalT $ do
213+ (s, tg) <- ask
214+ t <- lift $ lift $ newTag tg
215+ tellEvent $ fmapCheap (NonEmptyDeferred.singleton . RequestEnvelope (Just t)) e
216+ pure $ selectTag s t
217+ requesting_ e = RequesterInternalT $ do
218+ tellEvent $ fmapCheap (NonEmptyDeferred.singleton . RequestEnvelope Nothing) e
219+
220+instance (Adjustable t m, MonadHold t m) => Adjustable t (RequesterInternalT s t request response m) where
221+ {-# INLINABLE runWithReplace #-}
222+ runWithReplace (RequesterInternalT a0) a' = RequesterInternalT $ runWithReplace a0 (coerceEvent a')
223+ {-# INLINABLE traverseIntMapWithKeyWithAdjust #-}
224+ traverseIntMapWithKeyWithAdjust f dm0 dm' = RequesterInternalT $ traverseIntMapWithKeyWithAdjust (coerce . f) dm0 dm'
225+ {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
226+ traverseDMapWithKeyWithAdjust f dm0 dm' = RequesterInternalT $ traverseDMapWithKeyWithAdjust (coerce . f) dm0 dm'
227+ {-# INLINABLE traverseDMapWithKeyWithAdjustWithMove #-}
228+ traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = RequesterInternalT $ traverseDMapWithKeyWithAdjustWithMove (coerce . f) dm0 dm'
229+
230+instance (Adjustable t m, MonadHold t m) => Adjustable t (RequesterT t request response m) where
231+ {-# INLINABLE runWithReplace #-}
232+ runWithReplace (RequesterT a0) a' = RequesterT $ runWithReplace a0 (fmapCheap unRequesterT a')
233+ {-# INLINABLE traverseIntMapWithKeyWithAdjust #-}
234+ traverseIntMapWithKeyWithAdjust f dm0 dm' = RequesterT $ traverseIntMapWithKeyWithAdjust (\k v -> unRequesterT $ f k v) dm0 dm'
235+ {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
236+ traverseDMapWithKeyWithAdjust f dm0 dm' = RequesterT $ traverseDMapWithKeyWithAdjust (\k v -> unRequesterT $ f k v) dm0 dm'
237+ {-# INLINABLE traverseDMapWithKeyWithAdjustWithMove #-}
238+ traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = RequesterT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> unRequesterT $ f k v) dm0 dm'
239+
240+{-# INLINABLE runWithReplaceRequesterTWith #-}
241+runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
242+ , MonadFix m
243+ )
244+ => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
245+ -> RequesterT t request response m a
246+ -> Event t (RequesterT t request response m b)
247+ -> RequesterT t request response m (a, Event t b)
248+runWithReplaceRequesterTWith f (RequesterT a0) a' = RequesterT $ do
249+ pure undefined
250+
251+{-
252+import GHC.Exts (Any)
253+import Unsafe.Coerce
254+
255+--TODO: Make this module type-safe
256+
257+newtype TagMap (f :: * -> *) = TagMap (IntMap Any)
258+
259+newtype RequesterData f = RequesterData (TagMap (Entry f))
260+
261+data RequesterDataKey a where
262+ RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
263+ RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
264+ RequesterDataKey_Multi2 :: {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
265+ RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
266+
267+singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
268+singletonRequesterData rdk v = case rdk of
269+ RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
270+ RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
271+ RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
272+ RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
273+
274+requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
275+requesterDataToList (RequesterData m) = do
276+ k :=> Entry e <- tagMapToList m
277+ case myKeyType k of
278+ MyTagType_Single -> return $ RequesterDataKey_Single k :=> e
279+ MyTagType_Multi -> do
280+ (k', e') <- IntMap.toList e
281+ k'' :=> e'' <- requesterDataToList e'
282+ return $ RequesterDataKey_Multi k k' k'' :=> e''
283+ MyTagType_Multi2 -> do
284+ (k', e') <- Map.toList e
285+ (k'', e'') <- IntMap.toList e'
286+ k''' :=> e''' <- requesterDataToList e''
287+ return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
288+ MyTagType_Multi3 -> do
289+ (k', e') <- IntMap.toList e
290+ (k'', e'') <- IntMap.toList e'
291+ k''' :=> e''' <- requesterDataToList e''
292+ return $ RequesterDataKey_Multi3 k k' k'' k''' :=> e'''
293+
294+singletonTagMap :: forall f a. MyTag a -> f a -> TagMap f
295+singletonTagMap (MyTag k) v = TagMap $ IntMap.singleton k $ (unsafeCoerce :: f a -> Any) v
296+
297+tagMapToList :: forall f. TagMap f -> [DSum MyTag f]
298+tagMapToList (TagMap m) = f <$> IntMap.toList m
299+ where f :: (Int, Any) -> DSum MyTag f
300+ f (k, v) = MyTag k :=> (unsafeCoerce :: Any -> f a) v
301+
302+traverseTagMapWithKey :: forall t f g. Applicative t => (forall a. MyTag a -> f a -> t (g a)) -> TagMap f -> t (TagMap g)
303+traverseTagMapWithKey f (TagMap m) = TagMap <$> IntMap.traverseWithKey g m
304+ where
305+ g :: Int -> Any -> t Any
306+ g k v = (unsafeCoerce :: g a -> Any) <$> f (MyTag k) ((unsafeCoerce :: Any -> f a) v)
307+
308+-- | Runs in reverse to accommodate for the fact that we accumulate it in reverse
309+traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequesterData request -> m (RequesterData response)
310+traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWithKey go m --TODO: reverse this, since our tags are in reverse order
311+ where go :: forall x. MyTag x -> Entry request x -> m (Entry response x)
312+ go k (Entry request) = Entry <$> case myKeyType k of
313+ MyTagType_Single -> f request
314+ MyTagType_Multi -> traverse (traverseRequesterData f) request
315+ MyTagType_Multi2 -> traverse (traverse (traverseRequesterData f)) request
316+ MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
317+
318+-- | 'traverseRequesterData' with its arguments flipped
319+forRequesterData :: forall request response m. Applicative m => RequesterData request -> (forall a. request a -> m (response a)) -> m (RequesterData response)
320+forRequesterData r f = traverseRequesterData f r
321+
322+data MyTagType :: * -> * where
323+ MyTagType_Single :: MyTagType (Single a)
324+ MyTagType_Multi :: MyTagType Multi
325+ MyTagType_Multi2 :: MyTagType (Multi2 k)
326+ MyTagType_Multi3 :: MyTagType Multi3
327+
328+myKeyType :: MyTag x -> MyTagType x
329+myKeyType (MyTag k) = case k .&. 0x3 of
330+ 0x0 -> unsafeCoerce MyTagType_Single
331+ 0x1 -> unsafeCoerce MyTagType_Multi
332+ 0x2 -> unsafeCoerce MyTagType_Multi2
333+ 0x3 -> unsafeCoerce MyTagType_Multi3
334+ t -> error $ "Reflex.Requester.Base.myKeyType: no such key type" <> show t
335+
336+data Single a
337+data Multi
338+data Multi2 (k :: * -> *)
339+data Multi3
340+
341+class MyTagTypeOffset x where
342+ myTagTypeOffset :: proxy x -> Int
343+
344+instance MyTagTypeOffset (Single a) where
345+ myTagTypeOffset _ = 0x0
346+
347+instance MyTagTypeOffset Multi where
348+ myTagTypeOffset _ = 0x1
349+
350+instance MyTagTypeOffset (Multi2 k) where
351+ myTagTypeOffset _ = 0x2
352+
353+instance MyTagTypeOffset Multi3 where
354+ myTagTypeOffset _ = 0x3
355+
356+type family EntryContents request a where
357+ EntryContents request (Single a) = request a
358+ EntryContents request Multi = IntMap (RequesterData request)
359+ EntryContents request (Multi2 k) = Map (Some k) (IntMap (RequesterData request))
360+ EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
361+
362+newtype Entry request x = Entry { unEntry :: EntryContents request x }
363+
364+{-# INLINE singleEntry #-}
365+singleEntry :: f a -> Entry f (Single a)
366+singleEntry = Entry
367+
368+{-# INLINE multiEntry #-}
369+multiEntry :: IntMap (RequesterData f) -> Entry f Multi
370+multiEntry = Entry
371+
372+{-# INLINE unMultiEntry #-}
373+unMultiEntry :: Entry f Multi -> IntMap (RequesterData f)
374+unMultiEntry = unEntry
375+
376+-- | We use a hack here to pretend we have x ~ request a; we don't want to use a GADT, because GADTs (even with zero-size existential contexts) can't be newtypes
377+-- WARNING: This type should never be exposed. In particular, this is extremely unsound if a MyTag from one run of runRequesterT is ever compared against a MyTag from another
378+newtype MyTag x = MyTag Int deriving (Show, Eq, Ord, Enum)
379+
380+newtype MyTagWrap (f :: * -> *) x = MyTagWrap Int deriving (Show, Eq, Ord, Enum)
381+
382+{-# INLINE castMyTagWrap #-}
383+castMyTagWrap :: MyTagWrap f (Entry f x) -> MyTagWrap g (Entry g x)
384+castMyTagWrap = coerce
385+
386+instance GEq MyTag where
387+ (MyTag a) `geq` (MyTag b) =
388+ if a == b
389+ then Just $ unsafeCoerce Refl
390+ else Nothing
391+
392+instance GCompare MyTag where
393+ (MyTag a) `gcompare` (MyTag b) =
394+ case a `compare` b of
395+ LT -> GLT
396+ EQ -> unsafeCoerce GEQ
397+ GT -> GGT
398+
399+instance GEq (MyTagWrap f) where
400+ (MyTagWrap a) `geq` (MyTagWrap b) =
401+ if a == b
402+ then Just $ unsafeCoerce Refl
403+ else Nothing
404+
405+instance GCompare (MyTagWrap f) where
406+ (MyTagWrap a) `gcompare` (MyTagWrap b) =
407+ case a `compare` b of
408+ LT -> GLT
409+ EQ -> unsafeCoerce GEQ
410+ GT -> GGT
411+
412+data RequesterState t (request :: * -> *) = RequesterState
413+ { _requesterState_nextMyTag :: {-# UNPACK #-} !Int -- Starts at -4 and goes down by 4 each time, to accommodate two 'type' bits at the bottom
414+ , _requesterState_requests :: ![(Int, Event t Any)]
415+ }
416+
417+-- | A basic implementation of 'Requester'.
418+newtype RequesterT t request (response :: * -> *) m a = RequesterT { unRequesterT :: StateT (RequesterState t request) (ReaderT (EventSelectorInt t Any) m) a }
419+ deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
420+-- MonadAsyncException can't be derived on ghc-8.0.1; we use base-4.9.1 as a proxy for ghc-8.0.2
421+#if MIN_VERSION_base(4,9,1)
422+ , MonadAsyncException
423+#endif
424+ )
425+
426+
427+-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
428+-- requests are made, and responses should be provided in the input 'Event'.
429+-- The 'Tag' keys will be used to return the responses to the same place the
430+-- requests were issued.
431+runRequesterT :: (Reflex t, Monad m)
432+ => RequesterT t request response m a
433+ -> Event t (RequesterData response) --TODO: This DMap will be in reverse order, so we need to make sure the caller traverses it in reverse
434+ -> m (a, Event t (RequesterData request)) --TODO: we need to hide these 'MyTag's here, because they're unsafe to mix in the wild
435+runRequesterT (RequesterT a) responses = do
436+ (result, s) <- runReaderT (runStateT a $ RequesterState (-4) []) $ fanInt $
437+ coerceEvent responses
438+ return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
439+
440+-- | Map a function over the request and response of a 'RequesterT'
441+withRequesterT
442+ :: (Reflex t, MonadFix m)
443+ => (forall x. req x -> req' x) -- ^ The function to map over the request
444+ -> (forall x. rsp' x -> rsp x) -- ^ The function to map over the response
445+ -> RequesterT t req rsp m a -- ^ The internal 'RequesterT' whose input and output will be transformed
446+ -> RequesterT t req' rsp' m a -- ^ The resulting 'RequesterT'
447+withRequesterT freq frsp child = do
448+ rec let rsp = fmap (runIdentity . traverseRequesterData (Identity . frsp)) rsp'
449+ (a, req) <- lift $ runRequesterT child rsp
450+ rsp' <- fmap (flip selectInt 0 . fanInt . fmapCheap unMultiEntry) $ requesting' $
451+ fmapCheap (multiEntry . IntMap.singleton 0) $ fmap (runIdentity . traverseRequesterData (Identity . freq)) req
452+ return a
453+
454+instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
455+ type Request (RequesterT t request response m) = request
456+ type Response (RequesterT t request response m) = response
457+ requesting = fmap coerceEvent . responseFromTag . castMyTagWrap <=< tagRequest . (coerceEvent :: Event t (request a) -> Event t (Entry request (Single a)))
458+ requesting_ = void . tagRequest . fmapCheap singleEntry
459+
460+{-# INLINE tagRequest #-}
461+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))
462+tagRequest req = do
463+ old <- RequesterT get
464+ let n = _requesterState_nextMyTag old .|. myTagTypeOffset (Proxy :: Proxy x)
465+ t = MyTagWrap n
466+ RequesterT $ put $ RequesterState
467+ { _requesterState_nextMyTag = _requesterState_nextMyTag old - 0x4
468+ , _requesterState_requests = (n, (unsafeCoerce :: Event t (Entry request x) -> Event t Any) req) : _requesterState_requests old
469+ }
470+ return t
471+
472+{-# INLINE responseFromTag #-}
473+responseFromTag :: Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
474+responseFromTag (MyTagWrap t) = do
475+ responses :: EventSelectorInt t Any <- RequesterT ask
476+ return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
477+
478+instance MonadTrans (RequesterT t request response) where
479+ lift = RequesterT . lift . lift
480+
481+instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
482+ type Performable (RequesterT t request response m) = Performable m
483+ performEvent_ = lift . performEvent_
484+ performEvent = lift . performEvent
485+
486+instance MonadRef m => MonadRef (RequesterT t request response m) where
487+ type Ref (RequesterT t request response m) = Ref m
488+ newRef = lift . newRef
489+ readRef = lift . readRef
490+ writeRef r = lift . writeRef r
491+
492+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
493+ newEventWithTrigger = lift . newEventWithTrigger
494+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
495+
496+instance MonadReader r m => MonadReader r (RequesterT t request response m) where
497+ ask = lift ask
498+ local f (RequesterT a) = RequesterT $ mapStateT (mapReaderT $ local f) a
499+ reader = lift . reader
500+
501+instance (Reflex t, Adjustable t m, MonadHold t m, MonadFix m) => Adjustable t (RequesterT t request response m) where
502+ runWithReplace = runWithReplaceRequesterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
503+ traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElementsMap mergeIntIncremental
504+ {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
505+ traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental
506+ traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove
507+
508+requesting' :: (MyTagTypeOffset x, Monad m) => Event t (Entry request x) -> RequesterT t request response m (Event t (Entry response x))
509+requesting' = responseFromTag . castMyTagWrap <=< tagRequest
510+
511+{-# INLINABLE runWithReplaceRequesterTWith #-}
512+runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
513+ , MonadFix m
514+ )
515+ => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
516+ -> RequesterT t request response m a
517+ -> Event t (RequesterT t request response m b)
518+ -> RequesterT t request response m (a, Event t b)
519+runWithReplaceRequesterTWith f a0 a' = do
520+ rec na' <- numberOccurrencesFrom 1 a'
521+ responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requests --TODO: Investigate whether we can really get rid of the prompt stuff here
522+ let responses' = fanInt responses
523+ ((result0, requests0), v') <- f (runRequesterT a0 (selectInt responses' 0)) $ fmapCheap (\(n, a) -> fmap ((,) n) $ runRequesterT a $ selectInt responses' n) na'
524+ requests <- holdDyn (fmapCheap (IntMap.singleton 0) requests0) $ fmapCheap (\(n, (_, reqs)) -> fmapCheap (IntMap.singleton n) reqs) v'
525+ return (result0, fmapCheap (fst . snd) v')
526+
527+{-# INLINE traverseIntMapWithKeyWithAdjustRequesterTWith #-}
528+traverseIntMapWithKeyWithAdjustRequesterTWith :: forall t request response m v v' p.
529+ ( Reflex t
530+ , MonadHold t m
531+ , PatchTarget (p (Event t (IntMap (RequesterData request)))) ~ IntMap (Event t (IntMap (RequesterData request)))
532+ , Patch (p (Event t (IntMap (RequesterData request))))
533+ , Functor p
534+ , MonadFix m
535+ )
536+ => ( (IntMap.Key -> (IntMap.Key, v) -> m (Event t (IntMap (RequesterData request)), v'))
537+ -> IntMap (IntMap.Key, v)
538+ -> Event t (p (IntMap.Key, v))
539+ -> RequesterT t request response m (IntMap (Event t (IntMap (RequesterData request)), v'), Event t (p (Event t (IntMap (RequesterData request)), v')))
540+ )
541+ -> (p (Event t (IntMap (RequesterData request))) -> IntMap (Event t (IntMap (RequesterData request))))
542+ -> (Incremental t (p (Event t (IntMap (RequesterData request)))) -> Event t (IntMap (IntMap (RequesterData request))))
543+ -> (IntMap.Key -> v -> RequesterT t request response m v')
544+ -> IntMap v
545+ -> Event t (p v)
546+ -> RequesterT t request response m (IntMap v', Event t (p v'))
547+traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
548+ rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
549+ let responses :: EventSelectorInt t (IntMap (RequesterData response))
550+ responses = fanInt $ fmapCheap unpack response
551+ unpack :: Entry response Multi3 -> IntMap (IntMap (RequesterData response))
552+ unpack = unEntry
553+ pack :: IntMap (IntMap (RequesterData request)) -> Entry request Multi3
554+ pack = Entry
555+ f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
556+ f' k (n, v) = do
557+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ selectInt responses k --TODO: Instead of doing mapMaybeCheap, can we share a fanInt across all instances of a given key, or at least the ones that are adjacent in time?
558+ return (fmapCheap (IntMap.singleton n) myRequests, result)
559+ ndm' <- numberOccurrencesFrom 1 dm'
560+ (children0, children') <- base f' (fmap ((,) 0) dm0) $ fmap (\(n, dm) -> fmap ((,) n) dm) ndm' --TODO: Avoid this somehow, probably by adding some sort of per-cohort information passing to Adjustable
561+ let result0 = fmap snd children0
562+ result' = fforCheap children' $ fmap snd
563+ requests0 :: IntMap (Event t (IntMap (RequesterData request)))
564+ requests0 = fmap fst children0
565+ requests' :: Event t (p (Event t (IntMap (RequesterData request))))
566+ requests' = fforCheap children' $ fmap fst
567+ promptRequests :: Event t (IntMap (IntMap (RequesterData request)))
568+ promptRequests = coincidence $ fmapCheap (mergeInt . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
569+ requests <- holdIncremental requests0 requests'
570+ return (result0, result')
571+
572+{-# INLINE traverseDMapWithKeyWithAdjustRequesterTWith #-}
573+traverseDMapWithKeyWithAdjustRequesterTWith :: forall k t request response m v v' p p'.
574+ ( GCompare k
575+ , Reflex t
576+ , MonadHold t m
577+ , PatchTarget (p' (Some k) (Event t (IntMap (RequesterData request)))) ~ Map (Some k) (Event t (IntMap (RequesterData request)))
578+ , Patch (p' (Some k) (Event t (IntMap (RequesterData request))))
579+ , MonadFix m
580+ )
581+ => (forall k' v1 v2. GCompare k'
582+ => (forall a. k' a -> v1 a -> m (v2 a))
583+ -> DMap k' v1
584+ -> Event t (p k' v1)
585+ -> RequesterT t request response m (DMap k' v2, Event t (p k' v2))
586+ )
587+ -> (forall v1 v2. (forall a. v1 a -> v2 a) -> p k v1 -> p k v2)
588+ -> (forall v1 v2. (forall a. v1 a -> v2) -> p k v1 -> p' (Some k) v2)
589+ -> (forall v2. p' (Some k) v2 -> Map (Some k) v2)
590+ -> (forall a. Incremental t (p' (Some k) (Event t a)) -> Event t (Map (Some k) a))
591+ -> (forall a. k a -> v a -> RequesterT t request response m (v' a))
592+ -> DMap k v
593+ -> Event t (p k v)
594+ -> RequesterT t request response m (DMap k v', Event t (p k v'))
595+traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
596+ rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
597+ let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
598+ responses = fanMap $ fmapCheap unpack response
599+ unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
600+ unpack = unEntry
601+ pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
602+ pack = Entry
603+ f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
604+ f' k (Compose (n, v)) = do
605+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
606+ return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
607+ ndm' <- numberOccurrencesFrom 1 dm'
608+ (children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
609+ let result0 = DMap.map (snd . getCompose) children0
610+ result' = fforCheap children' $ mapPatch $ snd . getCompose
611+ requests0 :: Map (Some k) (Event t (IntMap (RequesterData request)))
612+ requests0 = weakenDMapWith (fst . getCompose) children0
613+ requests' :: Event t (p' (Some k) (Event t (IntMap (RequesterData request))))
614+ requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
615+ promptRequests :: Event t (Map (Some k) (IntMap (RequesterData request)))
616+ promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
617+ requests <- holdIncremental requests0 requests'
618+ return (result0, result')
619+
620+data Decoder rawResponse response =
621+ forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
622+
623+-- | Matches incoming responses with previously-sent requests
624+-- and uses the provided request "decoder" function to process
625+-- incoming responses.
626+matchResponsesWithRequests
627+ :: forall t rawRequest rawResponse request response m.
628+ ( MonadFix m
629+ , MonadHold t m
630+ , Reflex t
631+ )
632+ => (forall a. request a -> (rawRequest, rawResponse -> response a))
633+ -- ^ Given a request (from 'Requester'), produces the wire format of the
634+ -- request and a function used to process the associated response
635+ -> Event t (RequesterData request)
636+ -- ^ The outgoing requests
637+ -> Event t (Int, rawResponse)
638+ -- ^ The incoming responses, tagged by an identifying key
639+ -> m ( Event t (Map Int rawRequest)
640+ , Event t (RequesterData response)
641+ )
642+ -- ^ A map of outgoing wire-format requests and an event of responses keyed
643+ -- by the 'RequesterData' key of the associated outgoing request
644+matchResponsesWithRequests f send recv = do
645+ rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
646+ waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
647+ holdIncremental mempty $ leftmost
648+ [ fmap (\(_, outstanding, _) -> outstanding) outgoing
649+ , snd <$> incoming
650+ ]
651+ let outgoing = processOutgoing nextId send
652+ incoming = processIncoming waitingFor recv
653+ return (fmap (\(_, _, rawReqs) -> rawReqs) outgoing, fst <$> incoming)
654+ where
655+ -- Tags each outgoing request with an identifying integer key
656+ -- and returns the next available key, a map of response decoders
657+ -- for requests for which there are outstanding responses, and the
658+ -- raw requests to be sent out.
659+ processOutgoing
660+ :: Behavior t Int
661+ -- The next available key
662+ -> Event t (RequesterData request)
663+ -- The outgoing request
664+ -> Event t ( Int
665+ , PatchMap Int (Decoder rawResponse response)
666+ , Map Int rawRequest )
667+ -- The new next-available-key, a map of requests expecting responses, and the tagged raw requests
668+ processOutgoing nextId out = flip pushAlways out $ \dm -> do
669+ oldNextId <- sample nextId
670+ let (result, newNextId) = flip runState oldNextId $ forM (requesterDataToList dm) $ \(k :=> v) -> do
671+ n <- get
672+ put $ succ n
673+ let (rawReq, rspF) = f v
674+ return (n, rawReq, Decoder k rspF)
675+ patchWaitingFor = PatchMap $ Map.fromList $
676+ (\(n, _, dec) -> (n, Just dec)) <$> result
677+ toSend = Map.fromList $ (\(n, rawReq, _) -> (n, rawReq)) <$> result
678+ return (newNextId, patchWaitingFor, toSend)
679+ -- Looks up the each incoming raw response in a map of response
680+ -- decoders and returns the decoded response and a patch that can
681+ -- be used to clear the ID of the consumed response out of the queue
682+ -- of expected responses.
683+ processIncoming
684+ :: Incremental t (PatchMap Int (Decoder rawResponse response))
685+ -- A map of outstanding expected responses
686+ -> Event t (Int, rawResponse)
687+ -- A incoming response paired with its identifying key
688+ -> Event t (RequesterData response, PatchMap Int v)
689+ -- The decoded response and a patch that clears the outstanding responses queue
690+ processIncoming waitingFor inc = flip push inc $ \(n, rawRsp) -> do
691+ wf <- sample $ currentIncremental waitingFor
692+ case Map.lookup n wf of
693+ Nothing -> return Nothing -- TODO How should lookup failures be handled here? They shouldn't ever happen..
694+ Just (Decoder k rspF) -> do
695+ let rsp = rspF rawRsp
696+ return $ Just
697+ ( singletonRequesterData k rsp
698+ , PatchMap $ Map.singleton n Nothing
699+ )
700+-}