packages feed

extensible-effects-concurrent 0.15.0 → 0.16.0

raw patch · 22 files changed

+2077/−2926 lines, 22 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Control.Eff.Concurrent: -- | Type of observations visible on this observable
- Control.Eff.Concurrent: ServerCallback :: MessageSelector (Eff eff ApiServerCmd) -> (ExitReason 'Recoverable -> Eff eff ()) -> ServerCallback eff
- Control.Eff.Concurrent: [ApiHandler] :: {_castCallback :: Maybe (Api api 'Asynchronous -> Eff eff ApiServerCmd) " A cast will not return a result directly. This is used for async methods. This returns an 'ApiServerCmd' to the server loop.", _callCallback :: forall reply. Maybe (Api api ( 'Synchronous reply) -> (reply -> Eff eff ()) -> Eff eff ApiServerCmd) " A call is a blocking operation, the caller is blocked until this handler calls the reply continuation. This returns an 'ApiServerCmd' to the server loop.", _terminateCallback :: Maybe (ExitReason 'Recoverable -> Eff eff ()) " This callback is called with @Nothing@ if one of these things happen: * the process exits * '_callCallback' or '_castCallback' return 'StopApiServer' If the process exist peacefully the parameter is 'NotServerCallbacking', otherwise @Just "error message..."@ if the process exits with an error. The default behavior is defined in 'defaultTermination'."} -> ApiHandler api eff
- Control.Eff.Concurrent: [HandleNextRequest] :: ApiServerCmd
- Control.Eff.Concurrent: [SomeObserver] :: (Show (Server p), Typeable p, Observer p o) => Server p -> SomeObserver o
- Control.Eff.Concurrent: [StopApiServer] :: ExitReason 'Recoverable -> ApiServerCmd
- Control.Eff.Concurrent: [_requestHandlerSelector] :: ServerCallback eff -> MessageSelector (Eff eff ApiServerCmd)
- Control.Eff.Concurrent: [_terminationHandler] :: ServerCallback eff -> ExitReason 'Recoverable -> Eff eff ()
- Control.Eff.Concurrent: addObserver :: (SetMember Process (Process q) r, Member (ObserverState o) r, Observable o) => SomeObserver o -> Eff r ()
- Control.Eff.Concurrent: apiHandler :: (Api api 'Asynchronous -> Eff e ApiServerCmd) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ApiServerCmd) -> (ExitReason 'Recoverable -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent: apiHandlerForever :: (Api api 'Asynchronous -> Eff e ()) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ()) -> (ExitReason 'Recoverable -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent: callCallback :: forall api_a19pr eff_a19ps reply_a19pv. Getter (ApiHandler api_a19pr eff_a19ps) (Maybe (Api api_a19pr ( 'Synchronous reply_a19pv) -> (reply_a19pv -> Eff eff_a19ps ()) -> Eff eff_a19ps ApiServerCmd))
- Control.Eff.Concurrent: callHandler :: (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ApiServerCmd) -> ApiHandler api e
- Control.Eff.Concurrent: callHandlerForever :: (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent: castAndCallHandler :: (Api api 'Asynchronous -> Eff e ApiServerCmd) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ApiServerCmd) -> ApiHandler api e
- Control.Eff.Concurrent: castAndCallHandlerForever :: (Api api 'Asynchronous -> Eff e ()) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent: castCallback :: forall api_a19pr eff_a19ps. Lens' (ApiHandler api_a19pr eff_a19ps) (Maybe (Api api_a19pr 'Asynchronous -> Eff eff_a19ps ApiServerCmd))
- Control.Eff.Concurrent: castHandler :: (Api api 'Asynchronous -> Eff eff ApiServerCmd) -> ApiHandler api eff
- Control.Eff.Concurrent: castHandlerForever :: (Api api 'Asynchronous -> Eff eff ()) -> ApiHandler api eff
- Control.Eff.Concurrent: class (Typeable o, Typeable (Observation o)) => Observable o where {
- Control.Eff.Concurrent: class (Typeable p, Observable o) => Observer p o
- Control.Eff.Concurrent: data ApiHandler api eff
- Control.Eff.Concurrent: data ApiServerCmd
- Control.Eff.Concurrent: data CallbackObserver o
- Control.Eff.Concurrent: data Observers o
- Control.Eff.Concurrent: data Observing o
- Control.Eff.Concurrent: data ServerCallback eff
- Control.Eff.Concurrent: data SomeObserver o
- Control.Eff.Concurrent: defaultTermination :: forall q r. (HasCallStack, SetMember Process (Process q) r, Member (Logs LogMessage) r) => SchedulerProxy q -> ExitReason 'Recoverable -> Eff r ()
- Control.Eff.Concurrent: enqueueObservations :: forall o r q a. (SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, HasLogging IO r, HasLogging IO q, Member Interrupts r, Lifted IO q, HasCallStack) => SchedulerProxy q -> Server o -> Int -> Eff (ObservationQueueReader o : r) a -> Eff r a
- Control.Eff.Concurrent: enqueueObservationsRegistered :: forall o r q a. (ServesApi o r q, SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, HasLogging IO q, HasLogging IO r, Member Interrupts r, Lifted IO r, HasCallStack) => SchedulerProxy q -> Int -> Eff (ObservationQueueReader o : r) a -> Eff r a
- Control.Eff.Concurrent: forgetObserverMessage :: Observable o => SomeObserver o -> Api o 'Asynchronous
- Control.Eff.Concurrent: getSchedulerProxy :: HasScheduler q => SchedulerProxy q
- Control.Eff.Concurrent: notifyObserver :: (SetMember Process (Process q) r, Observable o, Observer p o, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Server p -> Server o -> Observation o -> Eff r ()
- Control.Eff.Concurrent: notifyObservers :: forall o r q. (Observable o, SetMember Process (Process q) r, Member (ObserverState o) r, Member Interrupts r) => SchedulerProxy q -> Observation o -> Eff r ()
- Control.Eff.Concurrent: notifySomeObserver :: (SetMember Process (Process q) r, Observable o, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Server o -> Observation o -> SomeObserver o -> Eff r ()
- Control.Eff.Concurrent: observationMessage :: Observer p o => Server o -> Observation o -> Api p 'Asynchronous
- Control.Eff.Concurrent: registerObserverMessage :: Observable o => SomeObserver o -> Api o 'Asynchronous
- Control.Eff.Concurrent: removeObserver :: (SetMember Process (Process q) r, Member (ObserverState o) r, Observable o, Member Interrupts r) => SomeObserver o -> Eff r ()
- Control.Eff.Concurrent: requestHandlerSelector :: forall eff_a19BH. Lens' (ServerCallback eff_a19BH) (MessageSelector (Eff eff_a19BH ApiServerCmd))
- Control.Eff.Concurrent: serve :: forall a effScheduler. (Servable a, SetMember Process (Process effScheduler) (ServerEff a), Member Interrupts (ServerEff a), HasCallStack) => SchedulerProxy effScheduler -> a -> Eff (ServerEff a) ()
- Control.Eff.Concurrent: spawnCallbackObserver :: forall o r q. (SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, Member (Logs LogMessage) q, Member Interrupts r, HasCallStack) => SchedulerProxy q -> (Server o -> Observation o -> Eff (InterruptableProcess q) ApiServerCmd) -> Eff r (Server (CallbackObserver o))
- Control.Eff.Concurrent: spawnLoggingObserver :: forall o r q. (SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, Member (Logs LogMessage) q, Member (Logs LogMessage) r, Member Interrupts r, HasCallStack) => SchedulerProxy q -> Eff r (Server (CallbackObserver o))
- Control.Eff.Concurrent: spawnServer :: forall a effScheduler eff. (Servable a, ServerEff a ~ InterruptableProcess effScheduler, SetMember Process (Process effScheduler) eff, Member Interrupts eff, HasCallStack) => SchedulerProxy effScheduler -> a -> Eff eff (ServerPids a)
- Control.Eff.Concurrent: spawnServerWithEffects :: forall a effScheduler eff. (Servable a, SetMember Process (Process effScheduler) (ServerEff a), SetMember Process (Process effScheduler) eff, Member Interrupts eff, Member Interrupts (ServerEff a), HasCallStack) => SchedulerProxy effScheduler -> a -> (Eff (ServerEff a) () -> Eff (InterruptableProcess effScheduler) ()) -> Eff eff (ServerPids a)
- Control.Eff.Concurrent: terminateCallback :: forall api_a19pr eff_a19ps. Lens' (ApiHandler api_a19pr eff_a19ps) (Maybe (ExitReason 'Recoverable -> Eff eff_a19ps ()))
- Control.Eff.Concurrent: terminationHandler :: forall eff_a19BH. Lens' (ServerCallback eff_a19BH) (ExitReason 'Recoverable -> Eff eff_a19BH ())
- Control.Eff.Concurrent: type HasScheduler q = (?_schedulerProxy :: SchedulerProxy q)
- Control.Eff.Concurrent: unhandledCallError :: forall p x r q. (Typeable p, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Api p ( 'Synchronous x) -> (x -> Eff r ()) -> Eff r ApiServerCmd
- Control.Eff.Concurrent: unhandledCastError :: forall p r q. (Typeable p, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Api p 'Asynchronous -> Eff r ApiServerCmd
- Control.Eff.Concurrent: withSchedulerProxy :: SchedulerProxy q -> (HasScheduler q => a) -> a
- Control.Eff.Concurrent.Api.Observer: -- | Type of observations visible on this observable
- Control.Eff.Concurrent.Api.Observer: [SomeObserver] :: (Show (Server p), Typeable p, Observer p o) => Server p -> SomeObserver o
- Control.Eff.Concurrent.Api.Observer: addObserver :: (SetMember Process (Process q) r, Member (ObserverState o) r, Observable o) => SomeObserver o -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: class (Typeable o, Typeable (Observation o)) => Observable o where {
- Control.Eff.Concurrent.Api.Observer: class (Typeable p, Observable o) => Observer p o
- Control.Eff.Concurrent.Api.Observer: data CallbackObserver o
- Control.Eff.Concurrent.Api.Observer: data Observers o
- Control.Eff.Concurrent.Api.Observer: data SomeObserver o
- Control.Eff.Concurrent.Api.Observer: data family Observation o;
- Control.Eff.Concurrent.Api.Observer: forgetObserverMessage :: Observable o => SomeObserver o -> Api o 'Asynchronous
- Control.Eff.Concurrent.Api.Observer: instance Control.Eff.Concurrent.Api.Observer.Observable o => Control.Eff.Concurrent.Api.Observer.Observer (Control.Eff.Concurrent.Api.Observer.CallbackObserver o) o
- Control.Eff.Concurrent.Api.Observer: instance GHC.Classes.Eq (Control.Eff.Concurrent.Api.Observer.SomeObserver o)
- Control.Eff.Concurrent.Api.Observer: instance GHC.Classes.Ord (Control.Eff.Concurrent.Api.Observer.SomeObserver o)
- Control.Eff.Concurrent.Api.Observer: instance GHC.Show.Show (Control.Eff.Concurrent.Api.Observer.Observation o) => GHC.Show.Show (Control.Eff.Concurrent.Api.Api (Control.Eff.Concurrent.Api.Observer.CallbackObserver o) r)
- Control.Eff.Concurrent.Api.Observer: instance GHC.Show.Show (Control.Eff.Concurrent.Api.Observer.SomeObserver o)
- Control.Eff.Concurrent.Api.Observer: notifyObserver :: (SetMember Process (Process q) r, Observable o, Observer p o, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Server p -> Server o -> Observation o -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: notifyObservers :: forall o r q. (Observable o, SetMember Process (Process q) r, Member (ObserverState o) r, Member Interrupts r) => SchedulerProxy q -> Observation o -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: notifySomeObserver :: (SetMember Process (Process q) r, Observable o, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Server o -> Observation o -> SomeObserver o -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: observationMessage :: Observer p o => Server o -> Observation o -> Api p 'Asynchronous
- Control.Eff.Concurrent.Api.Observer: registerObserverMessage :: Observable o => SomeObserver o -> Api o 'Asynchronous
- Control.Eff.Concurrent.Api.Observer: removeObserver :: (SetMember Process (Process q) r, Member (ObserverState o) r, Observable o, Member Interrupts r) => SomeObserver o -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: spawnCallbackObserver :: forall o r q. (SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, Member (Logs LogMessage) q, Member Interrupts r, HasCallStack) => SchedulerProxy q -> (Server o -> Observation o -> Eff (InterruptableProcess q) ApiServerCmd) -> Eff r (Server (CallbackObserver o))
- Control.Eff.Concurrent.Api.Observer: spawnLoggingObserver :: forall o r q. (SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, Member (Logs LogMessage) q, Member (Logs LogMessage) r, Member Interrupts r, HasCallStack) => SchedulerProxy q -> Eff r (Server (CallbackObserver o))
- Control.Eff.Concurrent.Api.Observer: }
- Control.Eff.Concurrent.Api.Observer.Queue: enqueueObservations :: forall o r q a. (SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, HasLogging IO r, HasLogging IO q, Member Interrupts r, Lifted IO q, HasCallStack) => SchedulerProxy q -> Server o -> Int -> Eff (ObservationQueueReader o : r) a -> Eff r a
- Control.Eff.Concurrent.Api.Observer.Queue: enqueueObservationsRegistered :: forall o r q a. (ServesApi o r q, SetMember Process (Process q) r, Typeable o, Show (Observation o), Observable o, HasLogging IO q, HasLogging IO r, Member Interrupts r, Lifted IO r, HasCallStack) => SchedulerProxy q -> Int -> Eff (ObservationQueueReader o : r) a -> Eff r a
- Control.Eff.Concurrent.Api.Server: -- <a>ProcessId</a>s in a type safe way, e.g. for a tuple instance of
- Control.Eff.Concurrent.Api.Server: -- this class <tt>(Server a, Server b)</tt>
- Control.Eff.Concurrent.Api.Server: -- | The is used to let the spawn function return multiple <a>Server</a>
- Control.Eff.Concurrent.Api.Server: ServerCallback :: MessageSelector (Eff eff ApiServerCmd) -> (ExitReason 'Recoverable -> Eff eff ()) -> ServerCallback eff
- Control.Eff.Concurrent.Api.Server: [ApiHandler] :: {_castCallback :: Maybe (Api api 'Asynchronous -> Eff eff ApiServerCmd) " A cast will not return a result directly. This is used for async methods. This returns an 'ApiServerCmd' to the server loop.", _callCallback :: forall reply. Maybe (Api api ( 'Synchronous reply) -> (reply -> Eff eff ()) -> Eff eff ApiServerCmd) " A call is a blocking operation, the caller is blocked until this handler calls the reply continuation. This returns an 'ApiServerCmd' to the server loop.", _terminateCallback :: Maybe (ExitReason 'Recoverable -> Eff eff ()) " This callback is called with @Nothing@ if one of these things happen: * the process exits * '_callCallback' or '_castCallback' return 'StopApiServer' If the process exist peacefully the parameter is 'NotServerCallbacking', otherwise @Just "error message..."@ if the process exits with an error. The default behavior is defined in 'defaultTermination'."} -> ApiHandler api eff
- Control.Eff.Concurrent.Api.Server: [HandleNextRequest] :: ApiServerCmd
- Control.Eff.Concurrent.Api.Server: [StopApiServer] :: ExitReason 'Recoverable -> ApiServerCmd
- Control.Eff.Concurrent.Api.Server: [_requestHandlerSelector] :: ServerCallback eff -> MessageSelector (Eff eff ApiServerCmd)
- Control.Eff.Concurrent.Api.Server: [_terminationHandler] :: ServerCallback eff -> ExitReason 'Recoverable -> Eff eff ()
- Control.Eff.Concurrent.Api.Server: apiHandler :: (Api api 'Asynchronous -> Eff e ApiServerCmd) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ApiServerCmd) -> (ExitReason 'Recoverable -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent.Api.Server: apiHandlerForever :: (Api api 'Asynchronous -> Eff e ()) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ()) -> (ExitReason 'Recoverable -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent.Api.Server: callCallback :: forall api_a19pr eff_a19ps reply_a19pv. Getter (ApiHandler api_a19pr eff_a19ps) (Maybe (Api api_a19pr ( 'Synchronous reply_a19pv) -> (reply_a19pv -> Eff eff_a19ps ()) -> Eff eff_a19ps ApiServerCmd))
- Control.Eff.Concurrent.Api.Server: callHandler :: (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ApiServerCmd) -> ApiHandler api e
- Control.Eff.Concurrent.Api.Server: callHandlerForever :: (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent.Api.Server: castAndCallHandler :: (Api api 'Asynchronous -> Eff e ApiServerCmd) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ApiServerCmd) -> ApiHandler api e
- Control.Eff.Concurrent.Api.Server: castAndCallHandlerForever :: (Api api 'Asynchronous -> Eff e ()) -> (forall r. Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ()) -> ApiHandler api e
- Control.Eff.Concurrent.Api.Server: castCallback :: forall api_a19pr eff_a19ps. Lens' (ApiHandler api_a19pr eff_a19ps) (Maybe (Api api_a19pr 'Asynchronous -> Eff eff_a19ps ApiServerCmd))
- Control.Eff.Concurrent.Api.Server: castHandler :: (Api api 'Asynchronous -> Eff eff ApiServerCmd) -> ApiHandler api eff
- Control.Eff.Concurrent.Api.Server: castHandlerForever :: (Api api 'Asynchronous -> Eff eff ()) -> ApiHandler api eff
- Control.Eff.Concurrent.Api.Server: class Servable a where {
- Control.Eff.Concurrent.Api.Server: data ApiHandler api eff
- Control.Eff.Concurrent.Api.Server: data ApiServerCmd
- Control.Eff.Concurrent.Api.Server: data ServerCallback eff
- Control.Eff.Concurrent.Api.Server: defaultTermination :: forall q r. (HasCallStack, SetMember Process (Process q) r, Member (Logs LogMessage) r) => SchedulerProxy q -> ExitReason 'Recoverable -> Eff r ()
- Control.Eff.Concurrent.Api.Server: instance (Control.Eff.Concurrent.Api.Server.ServerEff a Data.Type.Equality.~ Control.Eff.Concurrent.Api.Server.ServerEff b, Control.Eff.Concurrent.Api.Server.Servable a, Control.Eff.Concurrent.Api.Server.Servable b) => Control.Eff.Concurrent.Api.Server.Servable (a, b)
- Control.Eff.Concurrent.Api.Server: instance Control.DeepSeq.NFData Control.Eff.Concurrent.Api.Server.ApiServerCmd
- Control.Eff.Concurrent.Api.Server: instance Control.Eff.Concurrent.Api.Server.Servable (Control.Eff.Concurrent.Api.Server.ServerCallback eff)
- Control.Eff.Concurrent.Api.Server: instance Data.Default.Class.Default (Control.Eff.Concurrent.Api.Server.ApiHandler api eff)
- Control.Eff.Concurrent.Api.Server: instance Data.Typeable.Internal.Typeable a => Control.Eff.Concurrent.Api.Server.Servable (Control.Eff.Concurrent.Api.Server.ApiHandler a eff)
- Control.Eff.Concurrent.Api.Server: instance GHC.Base.Monoid (Control.Eff.Concurrent.Api.Server.ServerCallback eff)
- Control.Eff.Concurrent.Api.Server: instance GHC.Base.Semigroup (Control.Eff.Concurrent.Api.Server.ServerCallback eff)
- Control.Eff.Concurrent.Api.Server: instance GHC.Generics.Generic Control.Eff.Concurrent.Api.Server.ApiServerCmd
- Control.Eff.Concurrent.Api.Server: instance GHC.Show.Show Control.Eff.Concurrent.Api.Server.ApiServerCmd
- Control.Eff.Concurrent.Api.Server: requestHandlerSelector :: forall eff_a19BH. Lens' (ServerCallback eff_a19BH) (MessageSelector (Eff eff_a19BH ApiServerCmd))
- Control.Eff.Concurrent.Api.Server: serve :: forall a effScheduler. (Servable a, SetMember Process (Process effScheduler) (ServerEff a), Member Interrupts (ServerEff a), HasCallStack) => SchedulerProxy effScheduler -> a -> Eff (ServerEff a) ()
- Control.Eff.Concurrent.Api.Server: spawnServer :: forall a effScheduler eff. (Servable a, ServerEff a ~ InterruptableProcess effScheduler, SetMember Process (Process effScheduler) eff, Member Interrupts eff, HasCallStack) => SchedulerProxy effScheduler -> a -> Eff eff (ServerPids a)
- Control.Eff.Concurrent.Api.Server: spawnServerWithEffects :: forall a effScheduler eff. (Servable a, SetMember Process (Process effScheduler) (ServerEff a), SetMember Process (Process effScheduler) eff, Member Interrupts eff, Member Interrupts (ServerEff a), HasCallStack) => SchedulerProxy effScheduler -> a -> (Eff (ServerEff a) () -> Eff (InterruptableProcess effScheduler) ()) -> Eff eff (ServerPids a)
- Control.Eff.Concurrent.Api.Server: terminateCallback :: forall api_a19pr eff_a19ps. Lens' (ApiHandler api_a19pr eff_a19ps) (Maybe (ExitReason 'Recoverable -> Eff eff_a19ps ()))
- Control.Eff.Concurrent.Api.Server: terminationHandler :: forall eff_a19BH. Lens' (ServerCallback eff_a19BH) (ExitReason 'Recoverable -> Eff eff_a19BH ())
- Control.Eff.Concurrent.Api.Server: toServerCallback :: (Servable a, Member Interrupts (ServerEff a), SetMember Process (Process effScheduler) (ServerEff a)) => SchedulerProxy effScheduler -> a -> ServerCallback (ServerEff a)
- Control.Eff.Concurrent.Api.Server: unhandledCallError :: forall p x r q. (Typeable p, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Api p ( 'Synchronous x) -> (x -> Eff r ()) -> Eff r ApiServerCmd
- Control.Eff.Concurrent.Api.Server: unhandledCastError :: forall p r q. (Typeable p, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Api p 'Asynchronous -> Eff r ApiServerCmd
- Control.Eff.Concurrent.Api.Server2: (^:) :: forall (api1 :: Type) (apis2 :: [Type]) eff. HasCallStack => MessageCallback api1 eff -> MessageCallback apis2 eff -> MessageCallback (api1 : apis2) eff
- Control.Eff.Concurrent.Api.Server2: [AwaitNext] :: CallbackResult
- Control.Eff.Concurrent.Api.Server2: [InterruptCallback] :: (InterruptReason -> Eff eff CallbackResult) -> InterruptCallback eff
- Control.Eff.Concurrent.Api.Server2: [MessageCallback] :: MessageSelector a -> (a -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server2: [StopServer] :: InterruptReason -> CallbackResult
- Control.Eff.Concurrent.Api.Server2: apiServerLoop :: forall api eff serverEff. (HasCallStack, ToServerPids api, Member Interrupts serverEff, SetMember Process (Process eff) serverEff) => MessageCallback api serverEff -> InterruptCallback serverEff -> Eff serverEff ()
- Control.Eff.Concurrent.Api.Server2: class ToServerPids (t :: k) where {
- Control.Eff.Concurrent.Api.Server2: data CallbackResult
- Control.Eff.Concurrent.Api.Server2: data InterruptCallback eff
- Control.Eff.Concurrent.Api.Server2: data MessageCallback api eff
- Control.Eff.Concurrent.Api.Server2: data Observing o
- Control.Eff.Concurrent.Api.Server2: dropUnhandledMessages :: forall eff. HasCallStack => MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: exitOnUnhandled :: forall eff. HasCallStack => MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: fallbackHandler :: forall api eff. HasCallStack => MessageCallback api eff -> MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: handleAnyMessages :: forall eff. HasCallStack => (Dynamic -> Eff eff CallbackResult) -> MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => SchedulerProxy effScheduler -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server2: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => SchedulerProxy effScheduler -> (forall reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server2: handleCasts :: forall api eff. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous)) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server2: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => SchedulerProxy effScheduler -> (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server2: handleMessages :: forall eff a. (HasCallStack, NFData a, Typeable a) => (a -> Eff eff CallbackResult) -> MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: handleObservations :: Typeable o => (Server o -> Observation o -> Eff e CallbackResult) -> MessageCallback (Observing o) e
- Control.Eff.Concurrent.Api.Server2: handleProcessDowns :: forall eff. HasCallStack => (MonitorReference -> Eff eff CallbackResult) -> MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: handleSelectedMessages :: forall eff a. HasCallStack => MessageSelector a -> (a -> Eff eff CallbackResult) -> MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: infixr 5 ^:
- Control.Eff.Concurrent.Api.Server2: instance (Control.Eff.Concurrent.Api.Server2.ToServerPids api1, Control.Eff.Concurrent.Api.Server2.ToServerPids api2) => Control.Eff.Concurrent.Api.Server2.ToServerPids (api1 : api2)
- Control.Eff.Concurrent.Api.Server2: instance (Data.Typeable.Internal.Typeable o, Control.Eff.Concurrent.Api.Observer.Observable o) => Control.Eff.Concurrent.Api.Observer.Observer (Control.Eff.Concurrent.Api.Server2.Observing o) o
- Control.Eff.Concurrent.Api.Server2: instance Control.Eff.Concurrent.Api.Server2.ToServerPids '[]
- Control.Eff.Concurrent.Api.Server2: instance Control.Eff.Concurrent.Api.Server2.ToServerPids api1 => Control.Eff.Concurrent.Api.Server2.ToServerPids api1
- Control.Eff.Concurrent.Api.Server2: instance Data.Default.Class.Default (Control.Eff.Concurrent.Api.Server2.InterruptCallback eff)
- Control.Eff.Concurrent.Api.Server2: instance forall k (api :: k) (eff :: [* -> *]). Data.Default.Class.Default (Control.Eff.Concurrent.Api.Server2.MessageCallback api eff)
- Control.Eff.Concurrent.Api.Server2: instance forall k (api :: k) (eff :: [* -> *]). GHC.Base.Monoid (Control.Eff.Concurrent.Api.Server2.MessageCallback api eff)
- Control.Eff.Concurrent.Api.Server2: instance forall k (api :: k) (eff :: [* -> *]). GHC.Base.Semigroup (Control.Eff.Concurrent.Api.Server2.MessageCallback api eff)
- Control.Eff.Concurrent.Api.Server2: logUnhandledMessages :: forall eff. (Member (Logs LogMessage) eff, HasCallStack) => MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server2: spawnApiServer :: forall api eff. (ToServerPids api, HasCallStack) => MessageCallback api (InterruptableProcess eff) -> InterruptCallback (ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent.Api.Server2: spawnApiServerEffectful :: forall api eff serverEff. (HasCallStack, ToServerPids api, Member Interrupts serverEff, SetMember Process (Process eff) serverEff) => (forall b. Eff serverEff b -> Eff (InterruptableProcess eff) b) -> MessageCallback api serverEff -> InterruptCallback serverEff -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent.Api.Server2: spawnApiServerStateful :: forall api eff state. (HasCallStack, ToServerPids api) => Eff (InterruptableProcess eff) state -> MessageCallback api (State state : InterruptableProcess eff) -> InterruptCallback (State state : ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent.Api.Server2: spawnLinkApiServer :: forall api eff. (ToServerPids api, HasCallStack) => MessageCallback api (InterruptableProcess eff) -> InterruptCallback (ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent.Api.Server2: spawnLinkApiServerEffectful :: forall api eff serverEff. (HasCallStack, ToServerPids api, Member Interrupts serverEff, SetMember Process (Process eff) serverEff) => (forall b. Eff serverEff b -> Eff (InterruptableProcess eff) b) -> MessageCallback api serverEff -> InterruptCallback serverEff -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent.Api.Server2: stopServerOnInterrupt :: forall eff. HasCallStack => InterruptCallback eff
- Control.Eff.Concurrent.Api.Server2: toServerPids :: ToServerPids t => proxy t -> ProcessId -> ServerPids t
- Control.Eff.Concurrent.Api.Server2: type family ServerPids t;
- Control.Eff.Concurrent.Api.Server2: }
- Control.Eff.Concurrent.Process: getSchedulerProxy :: HasScheduler q => SchedulerProxy q
- Control.Eff.Concurrent.Process: type HasScheduler q = (?_schedulerProxy :: SchedulerProxy q)
- Control.Eff.Concurrent.Process: withSchedulerProxy :: SchedulerProxy q -> (HasScheduler q => a) -> a
+ Control.Eff.Concurrent: [Observer] :: (Show (Server p), Typeable p, Typeable o) => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o
+ Control.Eff.Concurrent: data Observer o
+ Control.Eff.Concurrent: data ObserverRegistry o
+ Control.Eff.Concurrent: handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r) => MessageCallback (ObserverRegistry o) r
+ Control.Eff.Concurrent: observed :: forall o r q. (SetMember Process (Process q) r, Member (ObserverState o) r, Member Interrupts r) => o -> Eff r ()
+ Control.Eff.Concurrent: spawnLinkObserverationQueue :: forall o q a. (Typeable o, Show o, HasLogging IO q, Lifted IO q, HasCallStack) => Server (ObserverRegistry o) -> Int -> Eff (ObservationQueueReader o : InterruptableProcess q) a -> Eff (InterruptableProcess q) a
+ Control.Eff.Concurrent: toObserver :: Typeable o => Server (Observer o) -> Observer o
+ Control.Eff.Concurrent: toObserverFor :: (Typeable a, Typeable o) => (o -> Api a 'Asynchronous) -> Server a -> Observer o
+ Control.Eff.Concurrent.Api.Observer: [Observer] :: (Show (Server p), Typeable p, Typeable o) => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o
+ Control.Eff.Concurrent.Api.Observer: data Observer o
+ Control.Eff.Concurrent.Api.Observer: data ObserverRegistry o
+ Control.Eff.Concurrent.Api.Observer: handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r) => (o -> Eff r CallbackResult) -> MessageCallback (Observer o) r
+ Control.Eff.Concurrent.Api.Observer: handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r) => MessageCallback (ObserverRegistry o) r
+ Control.Eff.Concurrent.Api.Observer: instance GHC.Classes.Eq (Control.Eff.Concurrent.Api.Observer.Observer o)
+ Control.Eff.Concurrent.Api.Observer: instance GHC.Classes.Ord (Control.Eff.Concurrent.Api.Observer.Observer o)
+ Control.Eff.Concurrent.Api.Observer: instance GHC.Show.Show (Control.Eff.Concurrent.Api.Observer.Observer o)
+ Control.Eff.Concurrent.Api.Observer: observed :: forall o r q. (SetMember Process (Process q) r, Member (ObserverState o) r, Member Interrupts r) => o -> Eff r ()
+ Control.Eff.Concurrent.Api.Observer: toObserver :: Typeable o => Server (Observer o) -> Observer o
+ Control.Eff.Concurrent.Api.Observer: toObserverFor :: (Typeable a, Typeable o) => (o -> Api a 'Asynchronous) -> Server a -> Observer o
+ Control.Eff.Concurrent.Api.Observer.Queue: spawnLinkObserverationQueue :: forall o q a. (Typeable o, Show o, HasLogging IO q, Lifted IO q, HasCallStack) => Server (ObserverRegistry o) -> Int -> Eff (ObservationQueueReader o : InterruptableProcess q) a -> Eff (InterruptableProcess q) a
+ Control.Eff.Concurrent.Api.Server: (^:) :: forall (api1 :: Type) (apis2 :: [Type]) eff. HasCallStack => MessageCallback api1 eff -> MessageCallback apis2 eff -> MessageCallback (api1 : apis2) eff
+ Control.Eff.Concurrent.Api.Server: [AwaitNext] :: CallbackResult
+ Control.Eff.Concurrent.Api.Server: [InterruptCallback] :: (InterruptReason -> Eff eff CallbackResult) -> InterruptCallback eff
+ Control.Eff.Concurrent.Api.Server: [MessageCallback] :: MessageSelector a -> (a -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: [StopServer] :: InterruptReason -> CallbackResult
+ Control.Eff.Concurrent.Api.Server: apiServerLoop :: forall api eff serverEff. (HasCallStack, ToServerPids api, Member Interrupts serverEff, SetMember Process (Process eff) serverEff) => MessageCallback api serverEff -> InterruptCallback serverEff -> Eff serverEff ()
+ Control.Eff.Concurrent.Api.Server: class ToServerPids (t :: k) where {
+ Control.Eff.Concurrent.Api.Server: data CallbackResult
+ Control.Eff.Concurrent.Api.Server: data InterruptCallback eff
+ Control.Eff.Concurrent.Api.Server: data MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: dropUnhandledMessages :: forall eff. HasCallStack => MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: exitOnUnhandled :: forall eff. HasCallStack => MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: fallbackHandler :: forall api eff. HasCallStack => MessageCallback api eff -> MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: handleAnyMessages :: forall eff. HasCallStack => (Dynamic -> Eff eff CallbackResult) -> MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCasts :: forall api eff. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous)) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleMessages :: forall eff a. (HasCallStack, NFData a, Typeable a) => (a -> Eff eff CallbackResult) -> MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: handleProcessDowns :: forall eff. HasCallStack => (MonitorReference -> Eff eff CallbackResult) -> MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: handleSelectedMessages :: forall eff a. HasCallStack => MessageSelector a -> (a -> Eff eff CallbackResult) -> MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: infixr 5 ^:
+ Control.Eff.Concurrent.Api.Server: instance (Control.Eff.Concurrent.Api.Server.ToServerPids api1, Control.Eff.Concurrent.Api.Server.ToServerPids api2) => Control.Eff.Concurrent.Api.Server.ToServerPids (api1 : api2)
+ Control.Eff.Concurrent.Api.Server: instance Control.Eff.Concurrent.Api.Server.ToServerPids '[]
+ Control.Eff.Concurrent.Api.Server: instance Control.Eff.Concurrent.Api.Server.ToServerPids api1 => Control.Eff.Concurrent.Api.Server.ToServerPids api1
+ Control.Eff.Concurrent.Api.Server: instance Data.Default.Class.Default (Control.Eff.Concurrent.Api.Server.InterruptCallback eff)
+ Control.Eff.Concurrent.Api.Server: instance forall k (api :: k) (eff :: [* -> *]). Data.Default.Class.Default (Control.Eff.Concurrent.Api.Server.MessageCallback api eff)
+ Control.Eff.Concurrent.Api.Server: instance forall k (api :: k) (eff :: [* -> *]). GHC.Base.Monoid (Control.Eff.Concurrent.Api.Server.MessageCallback api eff)
+ Control.Eff.Concurrent.Api.Server: instance forall k (api :: k) (eff :: [* -> *]). GHC.Base.Semigroup (Control.Eff.Concurrent.Api.Server.MessageCallback api eff)
+ Control.Eff.Concurrent.Api.Server: logUnhandledMessages :: forall eff. (Member (Logs LogMessage) eff, HasCallStack) => MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: spawnApiServer :: forall api eff. (ToServerPids api, HasCallStack) => MessageCallback api (InterruptableProcess eff) -> InterruptCallback (ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent.Api.Server: spawnApiServerEffectful :: forall api eff serverEff. (HasCallStack, ToServerPids api, Member Interrupts serverEff, SetMember Process (Process eff) serverEff) => (forall b. Eff serverEff b -> Eff (InterruptableProcess eff) b) -> MessageCallback api serverEff -> InterruptCallback serverEff -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent.Api.Server: spawnApiServerStateful :: forall api eff state. (HasCallStack, ToServerPids api) => Eff (InterruptableProcess eff) state -> MessageCallback api (State state : InterruptableProcess eff) -> InterruptCallback (State state : ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent.Api.Server: spawnLinkApiServer :: forall api eff. (ToServerPids api, HasCallStack) => MessageCallback api (InterruptableProcess eff) -> InterruptCallback (ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent.Api.Server: spawnLinkApiServerEffectful :: forall api eff serverEff. (HasCallStack, ToServerPids api, Member Interrupts serverEff, SetMember Process (Process eff) serverEff) => (forall b. Eff serverEff b -> Eff (InterruptableProcess eff) b) -> MessageCallback api serverEff -> InterruptCallback serverEff -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent.Api.Server: stopServerOnInterrupt :: forall eff. HasCallStack => InterruptCallback eff
- Control.Eff.Concurrent: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), Typeable result, HasCallStack, NFData result, Show result) => SchedulerProxy q -> Server api -> Api api ( 'Synchronous result) -> Eff r result
+ Control.Eff.Concurrent: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), Typeable result, HasCallStack, NFData result, Show result) => Server api -> Api api ( 'Synchronous result) -> Eff r result
- Control.Eff.Concurrent: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, Member Interrupts r) => SchedulerProxy q -> Api o ( 'Synchronous reply) -> Eff r reply
+ Control.Eff.Concurrent: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, Member Interrupts r) => Api o ( 'Synchronous reply) -> Eff r reply
- Control.Eff.Concurrent: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous)) => SchedulerProxy q -> Server o -> Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r) => Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent: data family Observation o;
+ Control.Eff.Concurrent: data family Api (api :: Type) (reply :: Synchronicity)
- Control.Eff.Concurrent: demonitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> MonitorReference -> Eff r ()
+ Control.Eff.Concurrent: demonitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => MonitorReference -> Eff r ()
- Control.Eff.Concurrent: exitBecause :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> ExitReason 'NoRecovery -> Eff r a
+ Control.Eff.Concurrent: exitBecause :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => ExitReason 'NoRecovery -> Eff r a
- Control.Eff.Concurrent: exitNormally :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r a
+ Control.Eff.Concurrent: exitNormally :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => Eff r a
- Control.Eff.Concurrent: exitOnInterrupt :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r a -> Eff r a
+ Control.Eff.Concurrent: exitOnInterrupt :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r) => Eff r a -> Eff r a
- Control.Eff.Concurrent: exitWithError :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> String -> Eff r a
+ Control.Eff.Concurrent: exitWithError :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => String -> Eff r a
- Control.Eff.Concurrent: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, HasScheduler q) => Eff r [Dynamic]
+ Control.Eff.Concurrent: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [Dynamic]
- Control.Eff.Concurrent: flushObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r [Observation o]
+ Control.Eff.Concurrent: flushObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r [o]
- Control.Eff.Concurrent: forgetObserver :: (SetMember Process (Process q) r, Observable o, Observer p o, Member Interrupts r) => SchedulerProxy q -> Server p -> Server o -> Eff r ()
+ Control.Eff.Concurrent: forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent: fromServer :: forall api_a17VQ api_a1868. Iso (Server api_a17VQ) (Server api_a1868) ProcessId ProcessId
+ Control.Eff.Concurrent: fromServer :: forall api_a17Gf api_a17PF. Iso (Server api_a17Gf) (Server api_a17PF) ProcessId ProcessId
- Control.Eff.Concurrent: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => SchedulerProxy effScheduler -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => SchedulerProxy effScheduler -> (forall reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => SchedulerProxy effScheduler -> (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent: handleObservations :: Typeable o => (Server o -> Observation o -> Eff e CallbackResult) -> MessageCallback (Observing o) e
+ Control.Eff.Concurrent: handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r) => (o -> Eff r CallbackResult) -> MessageCallback (Observer o) r
- Control.Eff.Concurrent: isProcessAlive :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r Bool
+ Control.Eff.Concurrent: isProcessAlive :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r Bool
- Control.Eff.Concurrent: linkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r ()
+ Control.Eff.Concurrent: linkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r ()
- Control.Eff.Concurrent: makeReference :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Eff r Int
+ Control.Eff.Concurrent: makeReference :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Int
- Control.Eff.Concurrent: monitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r MonitorReference
+ Control.Eff.Concurrent: monitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r MonitorReference
- Control.Eff.Concurrent: readObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r (Observation o)
+ Control.Eff.Concurrent: readObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r o
- Control.Eff.Concurrent: receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable a, NFData a, Show a) => SchedulerProxy q -> Timeout -> Eff r (Maybe a)
+ Control.Eff.Concurrent: receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a)
- Control.Eff.Concurrent: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => SchedulerProxy q -> (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Eff r Dynamic
+ Control.Eff.Concurrent: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Dynamic
- Control.Eff.Concurrent: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, Typeable a) => SchedulerProxy q -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, Typeable a) => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent: receiveMessage :: forall a r q. (HasCallStack, Typeable a, Show a, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Eff r a
+ Control.Eff.Concurrent: receiveMessage :: forall a r q. (HasCallStack, Typeable a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a
- Control.Eff.Concurrent: receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => SchedulerProxy q -> MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
+ Control.Eff.Concurrent: receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
- Control.Eff.Concurrent: receiveSelectedLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => SchedulerProxy q -> MessageSelector a -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent: receiveSelectedLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => MessageSelector a -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent: receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> MessageSelector a -> Eff r a
+ Control.Eff.Concurrent: receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, SetMember Process (Process q) r, Member Interrupts r) => MessageSelector a -> Eff r a
- Control.Eff.Concurrent: receiveWithMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r, Typeable a, Show a) => SchedulerProxy q -> ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a)
+ Control.Eff.Concurrent: receiveWithMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r, Typeable a, Show a) => ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a)
- Control.Eff.Concurrent: registerObserver :: (SetMember Process (Process q) r, Observable o, Observer p o, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Server p -> Server o -> Eff r ()
+ Control.Eff.Concurrent: registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent: self :: (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r ProcessId
+ Control.Eff.Concurrent: self :: (HasCallStack, SetMember Process (Process q) r) => Eff r ProcessId
- Control.Eff.Concurrent: sendAfter :: forall r q message. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable message, NFData message) => SchedulerProxy q -> ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
+ Control.Eff.Concurrent: sendAfter :: forall r q message. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
- Control.Eff.Concurrent: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Dynamic -> Eff r ()
+ Control.Eff.Concurrent: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> Dynamic -> Eff r ()
- Control.Eff.Concurrent: sendInterrupt :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> ProcessId -> InterruptReason -> Eff r ()
+ Control.Eff.Concurrent: sendInterrupt :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> InterruptReason -> Eff r ()
- Control.Eff.Concurrent: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => SchedulerProxy q -> ProcessId -> o -> Eff r ()
+ Control.Eff.Concurrent: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => ProcessId -> o -> Eff r ()
- Control.Eff.Concurrent: sendShutdown :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> ProcessId -> ExitReason 'NoRecovery -> Eff r ()
+ Control.Eff.Concurrent: sendShutdown :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> ExitReason 'NoRecovery -> Eff r ()
- Control.Eff.Concurrent: startTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Timeout -> Eff r TimerReference
+ Control.Eff.Concurrent: startTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Timeout -> Eff r TimerReference
- Control.Eff.Concurrent: tryReadObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r (Maybe (Observation o))
+ Control.Eff.Concurrent: tryReadObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r (Maybe o)
- Control.Eff.Concurrent: unlinkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r ()
+ Control.Eff.Concurrent: unlinkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r ()
- Control.Eff.Concurrent: withMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> (MonitorReference -> Eff r a) -> Eff r a
+ Control.Eff.Concurrent: withMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> (MonitorReference -> Eff r a) -> Eff r a
- Control.Eff.Concurrent: yieldProcess :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Eff r ()
+ Control.Eff.Concurrent: yieldProcess :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => Eff r ()
- Control.Eff.Concurrent.Api: fromServer :: forall api_a17VQ api_a1868. Iso (Server api_a17VQ) (Server api_a1868) ProcessId ProcessId
+ Control.Eff.Concurrent.Api: fromServer :: forall api_a17Gf api_a17PF. Iso (Server api_a17Gf) (Server api_a17PF) ProcessId ProcessId
- Control.Eff.Concurrent.Api.Client: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), Typeable result, HasCallStack, NFData result, Show result) => SchedulerProxy q -> Server api -> Api api ( 'Synchronous result) -> Eff r result
+ Control.Eff.Concurrent.Api.Client: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), Typeable result, HasCallStack, NFData result, Show result) => Server api -> Api api ( 'Synchronous result) -> Eff r result
- Control.Eff.Concurrent.Api.Client: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, Member Interrupts r) => SchedulerProxy q -> Api o ( 'Synchronous reply) -> Eff r reply
+ Control.Eff.Concurrent.Api.Client: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, Member Interrupts r) => Api o ( 'Synchronous reply) -> Eff r reply
- Control.Eff.Concurrent.Api.Client: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous)) => SchedulerProxy q -> Server o -> Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent.Api.Client: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent.Api.Client: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent.Api.Client: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r) => Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: forgetObserver :: (SetMember Process (Process q) r, Observable o, Observer p o, Member Interrupts r) => SchedulerProxy q -> Server p -> Server o -> Eff r ()
+ Control.Eff.Concurrent.Api.Observer: forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: registerObserver :: (SetMember Process (Process q) r, Observable o, Observer p o, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Server p -> Server o -> Eff r ()
+ Control.Eff.Concurrent.Api.Observer: registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent.Api.Observer.Queue: flushObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r [Observation o]
+ Control.Eff.Concurrent.Api.Observer.Queue: flushObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r [o]
- Control.Eff.Concurrent.Api.Observer.Queue: readObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r (Observation o)
+ Control.Eff.Concurrent.Api.Observer.Queue: readObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r o
- Control.Eff.Concurrent.Api.Observer.Queue: tryReadObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r (Maybe (Observation o))
+ Control.Eff.Concurrent.Api.Observer.Queue: tryReadObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, HasLogging IO r) => Eff r (Maybe o)
- Control.Eff.Concurrent.Api.Server: toServerPids :: Servable a => proxy a -> ProcessId -> ServerPids a
+ Control.Eff.Concurrent.Api.Server: toServerPids :: ToServerPids t => proxy t -> ProcessId -> ServerPids t
- Control.Eff.Concurrent.Api.Server: type family ServerPids a;
+ Control.Eff.Concurrent.Api.Server: type family ServerPids t;
- Control.Eff.Concurrent.Process: demonitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> MonitorReference -> Eff r ()
+ Control.Eff.Concurrent.Process: demonitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => MonitorReference -> Eff r ()
- Control.Eff.Concurrent.Process: exitBecause :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> ExitReason 'NoRecovery -> Eff r a
+ Control.Eff.Concurrent.Process: exitBecause :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => ExitReason 'NoRecovery -> Eff r a
- Control.Eff.Concurrent.Process: exitNormally :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r a
+ Control.Eff.Concurrent.Process: exitNormally :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => Eff r a
- Control.Eff.Concurrent.Process: exitOnInterrupt :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r a -> Eff r a
+ Control.Eff.Concurrent.Process: exitOnInterrupt :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r) => Eff r a -> Eff r a
- Control.Eff.Concurrent.Process: exitWithError :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> String -> Eff r a
+ Control.Eff.Concurrent.Process: exitWithError :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => String -> Eff r a
- Control.Eff.Concurrent.Process: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, HasScheduler q) => Eff r [Dynamic]
+ Control.Eff.Concurrent.Process: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [Dynamic]
- Control.Eff.Concurrent.Process: isProcessAlive :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r Bool
+ Control.Eff.Concurrent.Process: isProcessAlive :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r Bool
- Control.Eff.Concurrent.Process: linkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r ()
+ Control.Eff.Concurrent.Process: linkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r ()
- Control.Eff.Concurrent.Process: makeReference :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Eff r Int
+ Control.Eff.Concurrent.Process: makeReference :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Int
- Control.Eff.Concurrent.Process: monitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r MonitorReference
+ Control.Eff.Concurrent.Process: monitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r MonitorReference
- Control.Eff.Concurrent.Process: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => SchedulerProxy q -> (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent.Process: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent.Process: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Eff r Dynamic
+ Control.Eff.Concurrent.Process: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Dynamic
- Control.Eff.Concurrent.Process: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, Typeable a) => SchedulerProxy q -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent.Process: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, Typeable a) => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent.Process: receiveMessage :: forall a r q. (HasCallStack, Typeable a, Show a, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Eff r a
+ Control.Eff.Concurrent.Process: receiveMessage :: forall a r q. (HasCallStack, Typeable a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a
- Control.Eff.Concurrent.Process: receiveSelectedLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => SchedulerProxy q -> MessageSelector a -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent.Process: receiveSelectedLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => MessageSelector a -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent.Process: receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> MessageSelector a -> Eff r a
+ Control.Eff.Concurrent.Process: receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, SetMember Process (Process q) r, Member Interrupts r) => MessageSelector a -> Eff r a
- Control.Eff.Concurrent.Process: receiveWithMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r, Typeable a, Show a) => SchedulerProxy q -> ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a)
+ Control.Eff.Concurrent.Process: receiveWithMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r, Typeable a, Show a) => ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a)
- Control.Eff.Concurrent.Process: self :: (HasCallStack, SetMember Process (Process q) r) => SchedulerProxy q -> Eff r ProcessId
+ Control.Eff.Concurrent.Process: self :: (HasCallStack, SetMember Process (Process q) r) => Eff r ProcessId
- Control.Eff.Concurrent.Process: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Dynamic -> Eff r ()
+ Control.Eff.Concurrent.Process: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> Dynamic -> Eff r ()
- Control.Eff.Concurrent.Process: sendInterrupt :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> ProcessId -> InterruptReason -> Eff r ()
+ Control.Eff.Concurrent.Process: sendInterrupt :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> InterruptReason -> Eff r ()
- Control.Eff.Concurrent.Process: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => SchedulerProxy q -> ProcessId -> o -> Eff r ()
+ Control.Eff.Concurrent.Process: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => ProcessId -> o -> Eff r ()
- Control.Eff.Concurrent.Process: sendShutdown :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> ProcessId -> ExitReason 'NoRecovery -> Eff r ()
+ Control.Eff.Concurrent.Process: sendShutdown :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> ExitReason 'NoRecovery -> Eff r ()
- Control.Eff.Concurrent.Process: unlinkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> Eff r ()
+ Control.Eff.Concurrent.Process: unlinkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r ()
- Control.Eff.Concurrent.Process: withMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> ProcessId -> (MonitorReference -> Eff r a) -> Eff r a
+ Control.Eff.Concurrent.Process: withMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> (MonitorReference -> Eff r a) -> Eff r a
- Control.Eff.Concurrent.Process: yieldProcess :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => SchedulerProxy q -> Eff r ()
+ Control.Eff.Concurrent.Process: yieldProcess :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => Eff r ()
- Control.Eff.Concurrent.Process.Timer: cancelTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> TimerReference -> Eff r ()
+ Control.Eff.Concurrent.Process.Timer: cancelTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => TimerReference -> Eff r ()
- Control.Eff.Concurrent.Process.Timer: receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable a, NFData a, Show a) => SchedulerProxy q -> Timeout -> Eff r (Maybe a)
+ Control.Eff.Concurrent.Process.Timer: receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a)
- Control.Eff.Concurrent.Process.Timer: receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => SchedulerProxy q -> MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
+ Control.Eff.Concurrent.Process.Timer: receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
- Control.Eff.Concurrent.Process.Timer: sendAfter :: forall r q message. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable message, NFData message) => SchedulerProxy q -> ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
+ Control.Eff.Concurrent.Process.Timer: sendAfter :: forall r q message. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
- Control.Eff.Concurrent.Process.Timer: startTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => SchedulerProxy q -> Timeout -> Eff r TimerReference
+ Control.Eff.Concurrent.Process.Timer: startTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Timeout -> Eff r TimerReference

Files

ChangeLog.md view
@@ -1,5 +1,23 @@ # Changelog for extensible-effects-concurrent +## 0.16.0++API Stabilization and cleanup release with major API changes.++- Replace `Control.Eff.Concurrent.Api.Server` with+   `Control.Eff.Concurrent.Api.Server2` and rename+   `Control.Eff.Concurrent.Api.Server2` to+   `Control.Eff.Concurrent.Api.Server`++- Rewrite `Observer` and related modules like `Observer.Queue`+  - Remove all type classes+  - Rely on `Server2`+  - Remove `CallBackObserver`+  - Remove the observer support code in `Server2`++- Remove the `SchedulerProxy` parameter and tell library users to enable `AllowAmbiguousTypes` and `TypeApplications`+  - Remove dependent support code like `HasScheduler`+ ## 0.15.0  - Add `Api` `Request` and `Reply` types
README.md view
@@ -12,6 +12,16 @@  - Memory Leak Free `forever` +## GHC Extensions++In order to use the library you might need to activate some extension+in order to fight some ambiguous types, stemming from the flexibility to+choose different Scheduler implementations.++- AllowAmbiguousTypes+- TypeApplications++ ## Example  ```haskell@@ -28,7 +38,7 @@ main = defaultMain   (do     lift (threadDelay 100000) -- because of async logging-    firstExample forkIoScheduler+    firstExample     lift (threadDelay 100000) -- ... async logging   )     -- The SchedulerProxy paremeter contains the effects of a specific scheduler@@ -38,18 +48,18 @@ newtype WhoAreYou = WhoAreYou ProcessId deriving (Typeable, NFData, Show)  firstExample-  :: (HasLogging IO q) => SchedulerProxy q -> Eff (InterruptableProcess q) ()-firstExample px = do+  :: (HasLogging IO q) => Eff (InterruptableProcess q) ()+firstExample = do   person <- spawn     (do       logInfo "I am waiting for someone to ask me..."-      WhoAreYou replyPid <- receiveMessage px-      sendMessage px replyPid "Alice"+      WhoAreYou replyPid <- receiveMessage+      sendMessage replyPid "Alice"       logInfo (show replyPid ++ " just needed to know it.")     )-  me <- self px-  sendMessage px person (WhoAreYou me)-  personName <- receiveMessage px+  me <- self+  sendMessage person (WhoAreYou me)+  personName <- receiveMessage   logInfo ("I just met " ++ personName)  @@ -83,23 +93,6 @@  [![extensible-effects-concurrent LTS](http://stackage.org/package/extensible-effects-concurrent/badge/lts)](http://stackage.org/lts/package/extensible-effects-concurrent) -### Scheduler Variation--The ambiguity-flexibility trade-off introduced by using extensible effects-kicks in because the `Process` type has a `Spawn` clause, which needs to-know the `Eff`ects.--That is resolved by an omnipresent scheduler proxy parameter.--I will resolve this issue in one of these ways, but haven't decided:--- By using backpack - best option, apart from missing stack support--- By duplicating the code for each scheduler implementation--- By using implicit parameters (experimental use of that technique is in-  the logging part) - problem is that implicit parameter sometimes act weired-  and also might break compiler inlineing.  ### Other 
examples/example-1/Main.hs view
@@ -27,109 +27,86 @@ deriving instance Show (Api TestApi x)  main :: IO ()-main = defaultMain (example forkIoScheduler)+main = defaultMain example -mainProcessSpawnsAChildAndReturns-  :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> Eff r ()-mainProcessSpawnsAChildAndReturns px =-  void (spawn (void (receiveAnyMessage px)))+mainProcessSpawnsAChildAndReturns :: HasCallStack => Eff (InterruptableProcess q) ()+mainProcessSpawnsAChildAndReturns = void (spawn (void receiveAnyMessage)) -example-  :: ( HasCallStack-     , SetMember Process (Process q) r-     , Member Interrupts r-     , HasLogging IO r-     , HasLogging IO q-     )-  => SchedulerProxy q-  -> Eff r ()-example px = do-  me <- self px+example:: ( HasCallStack, HasLogging IO q) => Eff (InterruptableProcess q) ()+example = do+  me <- self   logInfo ("I am " ++ show me)-  server <- testServerLoop px+  server <- testServerLoop   logInfo ("Started server " ++ show server)   let go = do         lift (putStr "Enter something: ")         x <- lift getLine         case x of           ('K' : rest) -> do-            callRegistered px (TerminateError rest)+            callRegistered (TerminateError rest)             go           ('S' : _) -> do-            callRegistered px Terminate+            callRegistered Terminate             go           ('C' : _) -> do-            castRegistered px (Shout x)+            castRegistered (Shout x)             go           ('R' : rest) -> do-            replicateM_ (read rest) (castRegistered px (Shout x))+            replicateM_ (read rest) (castRegistered (Shout x))             go           ('q' : _) -> logInfo "Done."           _         -> do-            res <- callRegistered px (SayHello x)+            res <- callRegistered (SayHello x)             logInfo ("Result: " ++ show res)             go   registerServer server go  testServerLoop-  :: forall r q+  :: forall q    . ( HasCallStack-     , SetMember Process (Process q) r      , HasLogging IO q-     , Member Interrupts r      )-  => SchedulerProxy q-  -> Eff r (Server TestApi)-testServerLoop px = spawnServer px-  $ apiHandler handleCastTest handleCallTest handleTerminateTest+  => Eff (InterruptableProcess q) (Server TestApi)+testServerLoop = spawnApiServer+  (handleCastTest <> handleCalls handleCallTest) handleTerminateTest  where-  handleCastTest-    :: Api TestApi 'Asynchronous -> Eff (InterruptableProcess q) ApiServerCmd-  handleCastTest (Shout x) = do-    me <- self px+  handleCastTest = handleCasts $ \(Shout x) -> do+    me <- self     logInfo (show me ++ " Shouting: " ++ x)-    return HandleNextRequest-  handleCallTest-    :: Api TestApi ( 'Synchronous x)-    -> (x -> Eff (InterruptableProcess q) ())-    -> Eff (InterruptableProcess q) ApiServerCmd-  handleCallTest (SayHello "e1") _reply = do-    me <- self px+    return AwaitNext+  handleCallTest :: Api TestApi ('Synchronous r) -> (Eff (InterruptableProcess q) (Maybe r, CallbackResult) -> xxx) -> xxx+  handleCallTest (SayHello "e1") k = k $ do+    me <- self     logInfo (show me ++ " raising an error")     interrupt (ProcessError "No body loves me... :,(")-  handleCallTest (SayHello "e2") _reply = do-    me <- self px+  handleCallTest (SayHello "e2") k = k $ do+    me <- self     logInfo (show me ++ " throwing a MyException ")-    lift (Exc.throw MyException)-  handleCallTest (SayHello "self") reply = do-    me <- self px+    void (lift (Exc.throw MyException))+    pure (Nothing, AwaitNext)+  handleCallTest (SayHello "self") k = k $ do+    me <- self     logInfo (show me ++ " casting to self")-    cast px (asServer @TestApi me) (Shout "from me")-    void (reply False)-    return HandleNextRequest-  handleCallTest (SayHello "stop") reply = do-    me <- self px+    cast (asServer @TestApi me) (Shout "from me")+    return (Just False, AwaitNext)+  handleCallTest (SayHello "stop") k = k $ do+    me <- self     logInfo (show me ++ " stopping me")-    void (reply False)-    return (StopApiServer (ProcessError "test error"))-  handleCallTest (SayHello x) reply = do-    me <- self px+    return (Just False, StopServer (ProcessError "test error"))+  handleCallTest (SayHello x) k = k $ do+    me <- self     logInfo (show me ++ " Got Hello: " ++ x)-    void (reply (length x > 3))-    return HandleNextRequest-  handleCallTest Terminate reply = do-    me <- self px+    return (Just (length x > 3), AwaitNext)+  handleCallTest Terminate k = k $ do+    me <- self     logInfo (show me ++ " exiting")-    void (reply ())-    exitNormally px-  handleCallTest (TerminateError msg) reply = do-    me <- self px+    pure (Just (), StopServer ProcessFinished)+  handleCallTest (TerminateError msg) k = k $ do+    me <- self     logInfo (show me ++ " exiting with error: " ++ msg)-    void (reply ())-    exitWithError px msg-  handleTerminateTest msg = do-    me <- self px+    pure (Just (), StopServer (ProcessError msg))+  handleTerminateTest = InterruptCallback $ \msg -> do+    me <- self     logInfo (show me ++ " is exiting: " ++ show msg)     logProcessExit msg+    pure (StopServer msg)
examples/example-2/Main.hs view
@@ -11,11 +11,7 @@ import           Control.Concurrent  main :: IO ()-main = do-  defaultMain (void (altCounterExample SchedulerProxy))--  defaultMain (void (counterExample SchedulerProxy))-  print (schedulePure (counterExample SchedulerProxy))+main = defaultMain (void counterExample)  -- * First API @@ -24,36 +20,33 @@ data instance Api Counter x where   Inc :: Api Counter 'Asynchronous   Cnt :: Api Counter ('Synchronous Integer)-  ObserveCounter :: SomeObserver Counter -> Api Counter 'Asynchronous-  UnobserveCounter :: SomeObserver Counter -> Api Counter 'Asynchronous   deriving Typeable -altCounterExample+counterExample   :: (Member (Logs LogMessage) q, Lifted IO q)-  => SchedulerProxy q-  -> Eff (InterruptableProcess q) ()-altCounterExample px = do-  (c, (_sdp, cp)) <- altCounter+  => Eff (InterruptableProcess q) ()+counterExample = do+  (c, (co, (_sdp, cp))) <- spawnCounter   lift (threadDelay 500000)-  o <- logCounterObservations px+  o <- logCounterObservations   lift (threadDelay 500000)-  registerObserver px o c+  registerObserver o co   lift (threadDelay 500000)-  cast px c Inc+  cast c Inc   lift (threadDelay 500000)-  sendMessage px cp "test 123"-  cast px c Inc+  sendMessage cp "test 123"+  cast c Inc   lift (threadDelay 500000)-  cast px c Inc-  sendMessage px cp (12312312 :: Int)+  cast c Inc+  sendMessage cp (12312312 :: Int)   lift (threadDelay 500000)-  cast px c Inc+  cast c Inc   lift (threadDelay 500000)-  cast px c Inc+  cast c Inc   lift (threadDelay 500000)-  cast px c Inc+  cast c Inc   lift (threadDelay 500000)-  r <- call px c Cnt+  r <- call c Cnt   lift (threadDelay 500000)   lift (putStrLn ("r: " ++ show r))   lift (threadDelay 500000)@@ -65,17 +58,23 @@   Whoopediedoo :: Bool -> Api SupiDupi ('Synchronous (Maybe ()))   deriving Typeable -altCounter+data CounterChanged = CounterChanged Integer+  deriving (Show, Typeable)++spawnCounter   :: (Member (Logs LogMessage) q)   => Eff        (InterruptableProcess q)-       (Server Counter, (Server SupiDupi, ProcessId))-altCounter = spawnApiServerEffectful-  (manageObservers @Counter . evalState (0 :: Integer) . evalState+       ( Server Counter+       , ( Server (ObserverRegistry CounterChanged)+         , (Server SupiDupi, ProcessId)+         )+       )+spawnCounter = spawnApiServerEffectful+  (manageObservers @CounterChanged . evalState (0 :: Integer) . evalState     (Nothing :: Maybe (RequestOrigin (Api SupiDupi ( 'Synchronous (Maybe ())))))   )   (  handleCalls-      SP       (\case         Cnt ->           ($ do@@ -88,7 +87,7 @@          Inc -> do            val <- get @Integer            let val' = val + 1-           notifyObservers SP (CountChanged val')+           observed (CounterChanged val')            put val'            when (val' > 5) $ do              get@@ -102,15 +101,10 @@                )             return AwaitNext-         ObserveCounter s -> do-           addObserver s-           return AwaitNext-         UnobserveCounter s -> do-           removeObserver s-           return AwaitNext        )+  ^: handleObserverRegistration   ^: handleCallsDeferred-       SP+        (\origin ->          (\case            Whoopediedoo c -> do@@ -132,156 +126,16 @@  deriving instance Show (Api Counter x) -instance Observable Counter where-  data Observation Counter where-    CountChanged :: Integer -> Observation Counter-    deriving (Show, Typeable)-  registerObserverMessage = ObserveCounter-  forgetObserverMessage = UnobserveCounter- logCounterObservations-  :: ( SetMember Process (Process q) r-     , Member (Logs LogMessage) q-     , Member (Logs LogMessage) r-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> Eff r (Server (CallbackObserver Counter))-logCounterObservations px = spawnCallbackObserver-  px-  (\fromSvr msg -> do-    me <- self px-    logInfo (show me ++ " observed on: " ++ show fromSvr ++ ": " ++ show msg)-    return HandleNextRequest-  )---counterHandler-  :: forall r q-   . ( Member (State (Observers Counter)) r-     , Member (State Integer) r-     , SetMember Process (Process q) r-     , Member (Logs LogMessage) q-     , Member (Logs LogMessage) r-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> ApiHandler Counter r-counterHandler px = castAndCallHandler handleCastCounter handleCallCounter- where-  handleCastCounter :: Api Counter 'Asynchronous -> Eff r ApiServerCmd-  handleCastCounter (ObserveCounter o) =-    addObserver o >> return HandleNextRequest-  handleCastCounter (UnobserveCounter o) =-    removeObserver o >> return HandleNextRequest-  handleCastCounter Inc = do-    logInfo "Inc"-    modify (+ (1 :: Integer))-    currentCount <- get-    notifyObservers px (CountChanged currentCount)-    return HandleNextRequest-  handleCallCounter-    :: Api Counter ( 'Synchronous x) -> (x -> Eff r ()) -> Eff r ApiServerCmd-  handleCallCounter Cnt reply = do-    c <- get-    logInfo ("Cnt is " ++ show c)-    reply c-    return HandleNextRequest---- * Second API--data PocketCalc deriving Typeable--data instance Api PocketCalc x where-  Add :: Integer -> Api PocketCalc ('Synchronous Integer)-  AAdd :: Integer -> Api PocketCalc 'Asynchronous--deriving instance Show (Api PocketCalc x)--pocketCalcHandler-  :: forall r q-   . ( Member (State Integer) r-     , SetMember Process (Process q) r-     , Member (Logs LogMessage) r-     )-  => SchedulerProxy q-  -> ApiHandler PocketCalc r-pocketCalcHandler _ = castAndCallHandler handleCastCalc handleCallCalc- where-  handleCastCalc :: Api PocketCalc 'Asynchronous -> Eff r ApiServerCmd-  handleCastCalc (AAdd x) = do-    logInfo ("AsyncAdd " ++ show x)-    modify (+ x)-    c <- get @Integer-    logInfo ("Accumulator is " ++ show c)-    return HandleNextRequest-  handleCallCalc-    :: Api PocketCalc ( 'Synchronous x) -> (x -> Eff r ()) -> Eff r ApiServerCmd-  handleCallCalc (Add x) reply = do-    logInfo ("Add " ++ show x)-    modify (+ x)-    c <- get-    logInfo ("Accumulator is " ++ show c)-    reply c-    return HandleNextRequest--serverLoop-  :: forall r q-   . ( Member (Logs LogMessage) q-     , Member (Logs LogMessage) r-     , Member Interrupts r-     , SetMember Process (Process q) r-     )-  => SchedulerProxy q-  -> Eff r ()-serverLoop px = evalState @Integer-  0-  (manageObservers @Counter (serve px (counterHandler px, pocketCalcHandler px))-  )---- ** Counter client-counterExample-  :: ( SetMember Process (Process q) r-     , Member (Logs LogMessage) q-     , Member (Logs LogMessage) r-     , Member Interrupts r-     , q <:: r-     )-  => SchedulerProxy q-  -> Eff r Integer-counterExample px = execState (0 :: Integer) $ do-  let cnt sv = do-        r <- call px sv Cnt-        logInfo (show sv ++ " " ++ show r)-        modify (+ r)-  pid1 <- spawn (serverLoop px)-  pid2 <- spawn (serverLoop px)-  let cntServer1  = asServer @Counter pid1-      cntServer2  = asServer @Counter pid2-      calcServer1 = asServer @PocketCalc pid1-      calcServer2 = asServer @PocketCalc pid2-  cast px cntServer1 Inc-  cnt cntServer1-  cnt cntServer2-  co1 <- logCounterObservations px-  co2 <- logCounterObservations px-  registerObserver px co1 cntServer1-  registerObserver px co2 cntServer2-  cast px calcServer1 (AAdd 12313)-  cast px cntServer1  Inc-  cnt cntServer1-  cast px cntServer2 Inc-  cnt cntServer2-  registerObserver px co2 cntServer1-  registerObserver px co1 cntServer2-  cast px cntServer1 Inc-  void (call px calcServer2 (Add 878))-  cnt cntServer1-  cast px cntServer2 Inc-  cnt cntServer2-  forgetObserver px co2 cntServer1-  cast px cntServer1 Inc-  cnt cntServer1-  cast px cntServer2 Inc-  cnt cntServer2-  void $ sendShutdown px pid2 (NotRecovered (ProcessError "test test test"))+  :: (Member (Logs LogMessage) q)+  => Eff (InterruptableProcess q) (Observer CounterChanged)+logCounterObservations = do+  svr <- spawnApiServer+    (handleObservations+      (\msg -> do+        logInfo ("observed: " ++ show msg)+        return AwaitNext+      )+    )+    stopServerOnInterrupt+  pure (toObserver svr)
examples/example-4/Main.hs view
@@ -11,25 +11,25 @@ main = defaultMain   (do     lift (threadDelay 100000) -- because of async logging-    firstExample forkIoScheduler+    firstExample     lift (threadDelay 100000) -- ... async logging   )     -- The SchedulerProxy paremeter contains the effects of a specific scheduler     -- implementation. + newtype WhoAreYou = WhoAreYou ProcessId deriving (Typeable, NFData, Show) -firstExample-  :: (HasLogging IO q) => SchedulerProxy q -> Eff (InterruptableProcess q) ()-firstExample px = do+firstExample :: (HasLogging IO q) => Eff (InterruptableProcess q) ()+firstExample = do   person <- spawn     (do       logInfo "I am waiting for someone to ask me..."-      WhoAreYou replyPid <- receiveMessage px-      sendMessage px replyPid "Alice"+      WhoAreYou replyPid <- receiveMessage+      sendMessage replyPid "Alice"       logInfo (show replyPid ++ " just needed to know it.")     )-  me <- self px-  sendMessage px person (WhoAreYou me)-  personName <- receiveMessage px+  me <- self+  sendMessage person (WhoAreYou me)+  personName <- receiveMessage   logInfo ("I just met " ++ personName)
extensible-effects-concurrent.cabal view
@@ -1,5 +1,5 @@ name:           extensible-effects-concurrent-version:        0.15.0+version:        0.16.0 description:    Please see the README on GitHub at <https://github.com/sheyll/extensible-effects-concurrent#readme> synopsis:       Message passing concurrency as extensible-effect homepage:       https://github.com/sheyll/extensible-effects-concurrent#readme@@ -63,7 +63,6 @@                   Control.Eff.Concurrent,                   Control.Eff.Concurrent.Api,                   Control.Eff.Concurrent.Api.Client,-                  Control.Eff.Concurrent.Api.Server2,                   Control.Eff.Concurrent.Api.Server,                   Control.Eff.Concurrent.Process,                   Control.Eff.Concurrent.Process.Timer,@@ -76,6 +75,7 @@                 Control.Eff.Concurrent.Api.Request,                 Paths_extensible_effects_concurrent   default-extensions:+                     AllowAmbiguousTypes,                      BangPatterns,                      ConstraintKinds,                      DeriveFoldable,@@ -115,7 +115,8 @@               , lens   ghc-options: -Wall -threaded -fno-full-laziness -rtsopts -with-rtsopts=-N   default-language: Haskell2010-  default-extensions:   BangPatterns+  default-extensions:   AllowAmbiguousTypes+                      , BangPatterns                       , DataKinds                       , FlexibleContexts                       , FlexibleInstances@@ -142,7 +143,8 @@               , lens   ghc-options: -Wall -threaded -fno-full-laziness -rtsopts -with-rtsopts=-N   default-language: Haskell2010-  default-extensions:   BangPatterns+  default-extensions:   AllowAmbiguousTypes+                      , BangPatterns                       , DataKinds                       , FlexibleContexts                       , FlexibleInstances@@ -171,7 +173,8 @@               , lens   ghc-options: -Wall -threaded -fno-full-laziness -rtsopts -with-rtsopts=-N   default-language: Haskell2010-  default-extensions:   BangPatterns+  default-extensions:   AllowAmbiguousTypes+                      , BangPatterns                       , DataKinds                       , FlexibleContexts                       , FlexibleInstances@@ -197,7 +200,8 @@               , deepseq   ghc-options: -Wall -threaded -fno-full-laziness -rtsopts -with-rtsopts=-N   default-language: Haskell2010-  default-extensions:   BangPatterns+  default-extensions:   AllowAmbiguousTypes+                      , BangPatterns                       , DataKinds                       , FlexibleContexts                       , FlexibleInstances@@ -243,7 +247,8 @@               , HUnit               , stm   default-language: Haskell2010-  default-extensions:   BangPatterns+  default-extensions:   AllowAmbiguousTypes+                      , BangPatterns                       , DataKinds                       , FlexibleContexts                       , FlexibleInstances
src/Control/Eff/Concurrent.hs view
@@ -18,7 +18,7 @@     module Control.Eff.Concurrent.Api.Server   ,     -- ** /Server/ Functions for Providing APIs (new experimental)-    module Control.Eff.Concurrent.Api.Server2+    module Control.Eff.Concurrent.Api.Server   ,     -- ** Encapsulate 'Api's 'Cast's as well as 'Call's and their 'Reply's     module Control.Eff.Concurrent.Api.Request@@ -51,9 +51,6 @@                                                 , ConsProcess                                                 , ResumeProcess(..)                                                 , SchedulerProxy(..)-                                                , HasScheduler-                                                , getSchedulerProxy-                                                , withSchedulerProxy                                                 , thisSchedulerProxy                                                 , ProcessState(..)                                                 , yieldProcess@@ -165,7 +162,7 @@                                                 , RequestOrigin(..)                                                 , sendReply                                                 )-import           Control.Eff.Concurrent.Api.Server2+import           Control.Eff.Concurrent.Api.Server                                                 ( spawnApiServer                                                 , spawnLinkApiServer                                                 , spawnApiServerStateful@@ -189,52 +186,19 @@                                                 , ToServerPids(..)                                                 , InterruptCallback(..)                                                 , stopServerOnInterrupt-                                                , handleObservations-                                                , Observing()                                                 )--import           Control.Eff.Concurrent.Api.Server-                                                ( serve-                                                , spawnServer-                                                , spawnServerWithEffects-                                                , ApiHandler(..)-                                                , castCallback-                                                , callCallback-                                                , terminateCallback-                                                , apiHandler-                                                , apiHandlerForever-                                                , castHandler-                                                , castHandlerForever-                                                , callHandler-                                                , callHandlerForever-                                                , castAndCallHandler-                                                , castAndCallHandlerForever-                                                , ApiServerCmd(..)-                                                , unhandledCallError-                                                , unhandledCastError-                                                , defaultTermination-                                                -- , Servable(..)-                                                , ServerCallback(..)-                                                , requestHandlerSelector-                                                , terminationHandler-                                                ) import           Control.Eff.Concurrent.Api.Observer                                                 ( Observer(..)-                                                , Observable(..)-                                                , ObserverState-                                                , notifyObserver                                                 , registerObserver                                                 , forgetObserver-                                                , SomeObserver(..)-                                                , notifySomeObserver-                                                , Observers()+                                                , handleObservations+                                                , toObserver+                                                , toObserverFor+                                                , ObserverRegistry+                                                , ObserverState+                                                , handleObserverRegistration                                                 , manageObservers-                                                , addObserver-                                                , removeObserver-                                                , notifyObservers-                                                , CallbackObserver-                                                , spawnCallbackObserver-                                                , spawnLoggingObserver+                                                , observed                                                 ) import           Control.Eff.Concurrent.Api.Observer.Queue                                                 ( ObservationQueue()@@ -242,8 +206,7 @@                                                 , readObservationQueue                                                 , tryReadObservationQueue                                                 , flushObservationQueue-                                                , enqueueObservationsRegistered-                                                , enqueueObservations+                                                , spawnLinkObserverationQueue                                                 ) import           Control.Eff.Concurrent.Process.ForkIOScheduler                                                 ( schedule
src/Control/Eff/Concurrent/Api.hs view
@@ -24,15 +24,12 @@   ) where -import           Control.DeepSeq-import           Control.Eff import           Control.Eff.Concurrent.Process import           Control.Lens import           Data.Kind import           Data.Typeable                  ( Typeable                                                 , typeRep                                                 )-import           GHC.Generics  -- | This data family defines an API, a communication interface description -- between at least two processes. The processes act as __servers__ or@@ -78,8 +75,7 @@  instance Typeable api => Show (Server api) where   showsPrec d s@(Server c) =-    showParen (d >= 10)-      (showsPrec 11 (typeRep s) . showsPrec 11 c)+    showParen (d >= 10) (showsPrec 11 (typeRep s) . showsPrec 11 c)  makeLenses ''Server 
src/Control/Eff/Concurrent/Api/Client.hs view
@@ -36,11 +36,10 @@      , Typeable o      , Typeable (Api o 'Asynchronous)      )-  => SchedulerProxy q-  -> Server o+  => Server o   -> Api o 'Asynchronous   -> Eff r ()-cast px (Server pid) castMsg = sendMessage px pid (Cast $! castMsg)+cast (Server pid) castMsg = sendMessage pid (Cast $! castMsg)  -- | Send an 'Api' request and wait for the server to return a result value. --@@ -57,15 +56,14 @@      , NFData result      , Show result      )-  => SchedulerProxy q-  -> Server api+  => Server api   -> Api api ( 'Synchronous result)   -> Eff r result-call px (Server pidInternal) req = do-  fromPid <- self px-  callRef <- makeReference px+call (Server pidInternal) req = do+  fromPid <- self+  callRef <- makeReference   let requestMessage = Call callRef fromPid $! req-  sendMessage px pidInternal requestMessage+  sendMessage pidInternal requestMessage   let selectResult :: MessageSelector result       selectResult =         let extractResult@@ -73,7 +71,7 @@             extractResult (Reply _pxResult callRefMsg result) =               if callRefMsg == callRef then Just result else Nothing         in  selectMessageWith extractResult-  rres <- receiveWithMonitor px pidInternal selectResult+  rres <- receiveWithMonitor pidInternal selectResult   either (interrupt . becauseProcessIsDown) return rres  -- | Instead of passing around a 'Server' value and passing to functions like@@ -110,20 +108,18 @@      , Show reply      , Member Interrupts r      )-  => SchedulerProxy q-  -> Api o ( 'Synchronous reply)+  => Api o ( 'Synchronous reply)   -> Eff r reply-callRegistered px method = do+callRegistered method = do   serverPid <- whereIsServer-  call px serverPid method+  call serverPid method  -- | Like 'cast' but take the 'Server' from the reader provided by -- 'registerServer'. castRegistered   :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r)-  => SchedulerProxy q-  -> Api o 'Asynchronous+  => Api o 'Asynchronous   -> Eff r ()-castRegistered px method = do+castRegistered method = do   serverPid <- whereIsServer-  cast px serverPid method+  cast serverPid method
src/Control/Eff/Concurrent/Api/Observer.hs view
@@ -1,247 +1,218 @@ -- | Observer Effects ----- This module supports the implementation of observers and observables. One use--- case is event propagation. The tools in this module are tailored towards--- 'Api' servers/clients.+-- This module supports the implementation of observers and observables. Expected use+-- case is event propagation.+--+-- @since 0.16.0 module Control.Eff.Concurrent.Api.Observer-  ( -- * Observation API-    Observer(..)-  , Observable(..)-  , notifyObserver+  ( Observer(..)   , registerObserver   , forgetObserver-  -- ** Generalized observation-  , SomeObserver(..)-  , notifySomeObserver-  , Observers()+  , handleObservations+  , toObserver+  , toObserverFor+  , ObserverRegistry   , ObserverState+  , handleObserverRegistration   , manageObservers-  , addObserver-  , removeObserver-  , notifyObservers-  -- * Callback 'Observer'-  , CallbackObserver-  , spawnCallbackObserver-  , spawnLoggingObserver+  , observed   ) where -import           GHC.Stack-import           Data.Dynamic-import           Data.Set                       ( Set )-import qualified Data.Set                      as Set import           Control.Eff import           Control.Eff.Concurrent.Process import           Control.Eff.Concurrent.Api import           Control.Eff.Concurrent.Api.Client import           Control.Eff.Concurrent.Api.Server-import           Control.Eff.Log import           Control.Eff.State.Strict import           Control.Lens+import           Data.Dynamic+import           Data.Foldable+import           Data.Proxy+import           Data.Set                       ( Set )+import qualified Data.Set                      as Set+import           Data.Typeable                  ( typeRep )+import           GHC.Stack --- | An 'Api' index that support observation of the--- another 'Api' that is 'Observable'.-class (Typeable p, Observable o) => Observer p o where-  -- | Wrap the 'Observation' and the 'ProcessId' (i.e. the 'Server')-  -- that caused the observation into an 'Api' value that the-  -- 'Observable' understands.-  observationMessage :: Server o -> Observation o -> Api p 'Asynchronous+-- * Observers --- | An 'Api' index that supports registration and de-registration of--- 'Observer's.-class (Typeable o, Typeable (Observation o)) => Observable o where-  -- | Type of observations visible on this observable-  data Observation o-  -- | Return the 'Api' value for the 'cast_' that registeres an observer-  registerObserverMessage :: SomeObserver o -> Api o 'Asynchronous-  -- | Return the 'Api' value for the 'cast_' that de-registeres an observer-  forgetObserverMessage :: SomeObserver o -> Api o 'Asynchronous+-- | Describes a process that observes another via 'Asynchronous' 'Api' messages.+--+-- An observer consists of a filter and a process id. The filter converts an observation to+-- a message understood by the observer process, and the 'ProcessId' is used to send the message.+--+-- @since 0.16.0+data Observer o where+  Observer+    :: (Show (Server p), Typeable p, Typeable o)+    => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o --- | Send an 'Observation' to an 'Observer'-notifyObserver-  :: ( SetMember Process (Process q) r-     , Observable o-     , Observer p o-     , HasCallStack-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> Server p-  -> Server o-  -> Observation o-  -> Eff r ()-notifyObserver px observer observed observation =-  cast px observer (observationMessage observed observation)+instance Show (Observer o) where+  showsPrec d (Observer _ p) = showParen+    (d >= 10)+    (shows (typeRep (Proxy :: Proxy o)) . showString " observer: " . shows p) --- | Send the 'registerObserverMessage'+instance Ord (Observer o) where+  compare (Observer _ s1) (Observer _ s2) =+    compare (s1 ^. fromServer) (s2 ^. fromServer)++instance Eq (Observer o) where+  (==) (Observer _ s1) (Observer _ s2) =+    (==) (s1 ^. fromServer) (s2 ^. fromServer)++-- | And an 'Observer' to the set of reciepients for all observations reported by 'observed'.+--   Note that the observers are keyed by the observing process, i.e. a previous entry for the process+--   contained in the 'Observer' is overwritten. If you want multiple entries for a single process, just+--   combine several filter functions.+--+-- @since 0.16.0 registerObserver   :: ( SetMember Process (Process q) r-     , Observable o-     , Observer p o      , HasCallStack      , Member Interrupts r+     , Typeable o      )-  => SchedulerProxy q-  -> Server p-  -> Server o+  => Observer o+  -> Server (ObserverRegistry o)   -> Eff r ()-registerObserver px observer observed =-  cast px observed (registerObserverMessage (SomeObserver observer))+registerObserver observer observerRegistry =+  cast observerRegistry (RegisterObserver observer)  -- | Send the 'forgetObserverMessage'+--+-- @since 0.16.0 forgetObserver   :: ( SetMember Process (Process q) r-     , Observable o-     , Observer p o+     , HasCallStack      , Member Interrupts r+     , Typeable o      )-  => SchedulerProxy q-  -> Server p-  -> Server o+  => Observer o+  -> Server (ObserverRegistry o)   -> Eff r ()-forgetObserver px observer observed =-  cast px observed (forgetObserverMessage (SomeObserver observer))+forgetObserver observer observerRegistry =+  cast observerRegistry (ForgetObserver observer) --- | An existential wrapper around a 'Server' of an 'Observer'.--- Needed to support different types of observers to observe the--- same 'Observable' in a general fashion.-data SomeObserver o where-  SomeObserver :: (Show (Server p), Typeable p, Observer p o) => Server p -> SomeObserver o+-- ** Observer Support Functions -deriving instance Show (SomeObserver o)+-- | A minimal Api for handling observations.+-- This is one simple way of receiving observations - of course users can use+-- any other 'Asynchronous' 'Api' message type for receiving observations.+--+-- @since 0.16.0+data instance Api (Observer o) r where+  Observed :: o -> Api (Observer o) 'Asynchronous -instance Ord (SomeObserver o) where-  compare (SomeObserver (Server o1)) (SomeObserver (Server o2)) =-    compare o1 o2+-- | Based on the 'Api' instance for 'Observer' this simplified writing+-- a callback handler for observations. In order to register to+-- and 'ObservationRegistry' use 'toObserver'.+--+-- @since 0.16.0+handleObservations+  :: (HasCallStack, Typeable o, SetMember Process (Process q) r)+  => (o -> Eff r CallbackResult)+  -> MessageCallback (Observer o) r+handleObservations k = handleCasts+  (\case+    Observed o -> k o+  ) -instance Eq (SomeObserver o) where-  (==) (SomeObserver (Server o1)) (SomeObserver (Server o2)) =-    o1 == o2+-- | Use a 'Server' as an 'Observer' for 'handleObserved'.+--+-- @since 0.16.0+toObserver :: Typeable o => Server (Observer o) -> Observer o+toObserver = toObserverFor Observed --- | Send an 'Observation' to 'SomeObserver'.-notifySomeObserver-  :: ( SetMember Process (Process q) r-     , Observable o-     , HasCallStack-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> Server o-  -> Observation o-  -> SomeObserver o-  -> Eff r ()-notifySomeObserver px observed observation (SomeObserver observer) =-  notifyObserver px observer observed observation+-- | Create an 'Observer' that conditionally accepts all observeration of the+-- given type and applies the given function to them; the function takes an observation and returns an 'Api'+-- cast that the observer server is compatible to.+--+-- @since 0.16.0+toObserverFor+  :: (Typeable a, Typeable o)+  => (o -> Api a 'Asynchronous)+  -> Server a+  -> Observer o+toObserverFor wrapper = Observer (Just . wrapper) --- ** Manage 'Observers's+-- * Managing Observers --- | Internal state for 'manageObservers'-data Observers o =-  Observers { _observers :: Set (SomeObserver o) }+-- | An 'Api' for managing 'Observer's, encompassing  registration and de-registration of+-- 'Observer's.+--+-- @since 0.16.0+data ObserverRegistry o --- | Alias for the effect that contains the observers managed by 'manageObservers'-type ObserverState o = State (Observers o)+-- | Api for managing observers. This can be added to any server for any number of different observation types.+-- The functions 'manageObservers' and 'handleObserverApi' are used to include observer handling;+--+-- @since 0.16.0+data instance Api (ObserverRegistry o) r where+  RegisterObserver :: Observer o -> Api (ObserverRegistry o) 'Asynchronous+  ForgetObserver :: Observer o -> Api (ObserverRegistry o) 'Asynchronous -observers :: Iso' (Observers o) (Set (SomeObserver o))-observers = iso _observers Observers --- | Keep track of registered 'Observer's Observers can be added and removed,--- and an 'Observation' can be sent to all registerd observers at once.-manageObservers :: Eff (ObserverState o ': r) a -> Eff r a-manageObservers = evalState (Observers Set.empty)---- | Add an 'Observer' to the 'Observers' managed by 'manageObservers'.-addObserver-  :: (SetMember Process (Process q) r, Member (ObserverState o) r, Observable o)-  => SomeObserver o-  -> Eff r ()-addObserver = modify . over observers . Set.insert---- | Delete an 'Observer' from the 'Observers' managed by 'manageObservers'.-removeObserver-  :: ( SetMember Process (Process q) r-     , Member (ObserverState o) r-     , Observable o-     , Member Interrupts r-     )-  => SomeObserver o-  -> Eff r ()-removeObserver = modify . over observers . Set.delete-+-- ** Api for integrating 'ObserverRegistry' into processes. --- | Send an 'Observation' to all 'SomeObserver's in the 'Observers' state.-notifyObservers-  :: forall o r q-   . ( Observable o+-- | Provide the implementation for the 'Observerd' Api, this handled 'RegisterObserver' and 'ForgetObserver'+-- messages. It also adds the 'ObserverState' constraint to the effect list.+--+-- @since 0.16.0+handleObserverRegistration+  :: forall o q r+   . ( HasCallStack+     , Typeable o      , SetMember Process (Process q) r      , Member (ObserverState o) r-     , Member Interrupts r      )-  => SchedulerProxy q-  -> Observation o-  -> Eff r ()-notifyObservers px observation = do-  me <- asServer @o <$> self px-  os <- view observers <$> get-  mapM_ (notifySomeObserver px me observation) os+  => MessageCallback (ObserverRegistry o) r+handleObserverRegistration = handleCasts+  (\case+    RegisterObserver ob ->+      get @(Observers o)+        >>= put+        .   over observers (Set.insert ob)+        >>  pure AwaitNext+    ForgetObserver ob ->+      get @(Observers o)+        >>= put+        .   over observers (Set.delete ob)+        >>  pure AwaitNext+  ) --- | An 'Observer' that schedules the observations to an effectful callback.-data CallbackObserver o-  deriving Typeable -data instance Api (CallbackObserver o) r where-  CbObserved :: (Typeable o, Typeable (Observation o)) =>-             Server o -> Observation o -> Api (CallbackObserver o) 'Asynchronous-  deriving Typeable+-- | Keep track of registered 'Observer's Observers can be added and removed,+-- and an 'Observation' can be sent to all registerd observers at once.+--+-- @since 0.16.0+manageObservers :: Eff (ObserverState o ': r) a -> Eff r a+manageObservers = evalState (Observers Set.empty) -deriving instance Show (Observation o) => Show (Api (CallbackObserver o) r)+-- | Internal state for 'manageObservers'+data Observers o =+  Observers { _observers :: Set (Observer o) } -instance (Observable o) => Observer (CallbackObserver o) o where-  observationMessage = CbObserved+-- | Alias for the effect that contains the observers managed by 'manageObservers'+type ObserverState o = State (Observers o) --- | Start a new process for an 'Observer' that schedules--- all observations to an effectful callback.-spawnCallbackObserver-  :: forall o r q-   . ( SetMember Process (Process q) r-     , Typeable o-     , Show (Observation o)-     , Observable o-     , Member (Logs LogMessage) q-     , Member Interrupts r-     , HasCallStack-     )-  => SchedulerProxy q-  -> (  Server o-     -> Observation o-     -> Eff (InterruptableProcess q) ApiServerCmd-     )-  -> Eff r (Server (CallbackObserver o))-spawnCallbackObserver px onObserve = spawnServerWithEffects-  px-  (castHandler handleCastCbo)-  id-  where handleCastCbo (CbObserved fromSvr v) = onObserve fromSvr v+observers :: Iso' (Observers o) (Set (Observer o))+observers = iso _observers Observers --- | Start a new process for an 'Observer' that schedules--- all observations to an effectful callback.+-- | Report an observation to all observers.+-- The process needs to 'manageObservers' and to 'handleObserverRegistration'. ----- @since 0.3.0.0-spawnLoggingObserver+-- @since 0.16.0+observed   :: forall o r q    . ( SetMember Process (Process q) r-     , Typeable o-     , Show (Observation o)-     , Observable o-     , Member (Logs LogMessage) q-     , Member (Logs LogMessage) r+     , Member (ObserverState o) r      , Member Interrupts r-     , HasCallStack      )-  => SchedulerProxy q-  -> Eff r (Server (CallbackObserver o))-spawnLoggingObserver px = spawnCallbackObserver-  px-  (\s o ->-    logDebug (show s ++ " OBSERVED: " ++ show o) >> return HandleNextRequest-  )+  => o+  -> Eff r ()+observed observation = do+  os <- view observers <$> get+  mapM_ notifySomeObserver os+ where+  notifySomeObserver (Observer messageFilter receiver) =+    traverse_ (cast receiver) (messageFilter observation)
src/Control/Eff/Concurrent/Api/Observer/Queue.hs view
@@ -1,17 +1,17 @@--- | Capture 'Observation's and enqueue then into an STM 'TBQeueu'.+-- | A small process to capture and _share_ observation's by enqueueing them into an STM 'TBQeueu'. module Control.Eff.Concurrent.Api.Observer.Queue   ( ObservationQueue()   , ObservationQueueReader   , readObservationQueue   , tryReadObservationQueue   , flushObservationQueue-  , enqueueObservationsRegistered-  , enqueueObservations+  , spawnLinkObserverationQueue   ) where  import           Control.Concurrent.STM import           Control.Eff+import           Control.Eff.Extend import           Control.Eff.ExceptionExtra     ( ) import           Control.Eff.Lift import           Control.Eff.Concurrent.Process@@ -29,8 +29,8 @@ import           GHC.Stack  -- | Contains a 'TBQueue' capturing observations received by 'enqueueObservationsRegistered'--- or 'enqueueObservations'.-newtype ObservationQueue a = ObservationQueue (TBQueue (Observation a))+-- or 'spawnLinkObserverationQueue'.+newtype ObservationQueue a = ObservationQueue (TBQueue a)  -- | A 'Reader' for an 'ObservationQueue'. type ObservationQueueReader a = Reader (ObservationQueue a)@@ -38,9 +38,8 @@ logPrefix :: forall o proxy . (HasCallStack, Typeable o) => proxy o -> String logPrefix px = "observation queue: " ++ show (typeRep px) --- | Read queued observations captured by observing a 'Server' that implements--- an 'Observable' 'Api' using 'enqueueObservationsRegistered' or 'enqueueObservations'.--- This blocks until the next 'Observation' received. For a non-blocking+-- | Read queued observations captured and enqueued in the shared 'TBQueue' by 'spawnLinkObserverationQueue'.+-- This blocks until something was captured or an interrupt or exceptions was thrown. For a non-blocking -- variant use 'tryReadObservationQueue' or 'flushObservationQueue'. readObservationQueue   :: forall o r@@ -50,14 +49,13 @@      , Typeable o      , HasLogging IO r      )-  => Eff r (Observation o)+  => Eff r o readObservationQueue = do   ObservationQueue q <- ask @(ObservationQueue o)   liftIO (atomically (readTBQueue q)) --- | Read queued observations captured by observing a 'Server' that implements--- an 'Observable' 'Api' using 'enqueueObservationsRegistered' or 'enqueueObservations'.--- Return the next 'Observation' immediately or 'Nothing' if the queue is empty.+-- | Read queued observations captured and enqueued in the shared 'TBQueue' by 'spawnLinkObserverationQueue'.+-- Return the oldest enqueued observation immediately or 'Nothing' if the queue is empty. -- Use 'readObservationQueue' to block until an observation is observed. tryReadObservationQueue   :: forall o r@@ -67,12 +65,12 @@      , Typeable o      , HasLogging IO r      )-  => Eff r (Maybe (Observation o))+  => Eff r (Maybe o) tryReadObservationQueue = do   ObservationQueue q <- ask @(ObservationQueue o)   liftIO (atomically (tryReadTBQueue q)) --- | Read all currently queued 'Observation's captured by 'enqueueObservations'.+-- | Read at once all currently queued observations captured and enqueued in the shared 'TBQueue' by 'spawnLinkObserverationQueue'. -- This returns immediately all currently enqueued 'Observation's. For a blocking -- variant use 'readObservationQueue'. flushObservationQueue@@ -83,58 +81,29 @@      , Typeable o      , HasLogging IO r      )-  => Eff r [Observation o]+  => Eff r [o] flushObservationQueue = do   ObservationQueue q <- ask @(ObservationQueue o)   liftIO (atomically (flushTBQueue q)) --- | Observe a(the) registered 'Server' that implements an 'Observable' 'Api'.--- Based on 'enqueueObservations'.-enqueueObservationsRegistered-  :: forall o r q a-   . ( ServesApi o r q-     , SetMember Process (Process q) r-     , Typeable o-     , Show (Observation o)-     , Observable o-     , HasLogging IO q-     , HasLogging IO r-     , Member Interrupts r-     , Lifted IO r-     , HasCallStack-     )-  => SchedulerProxy q-  -> Int-  -> Eff (ObservationQueueReader o ': r) a-  -> Eff r a-enqueueObservationsRegistered px queueLimit k = do-  oSvr <- whereIsServer @o-  enqueueObservations px oSvr queueLimit k --- | Observe a 'Server' that implements an 'Observable' 'Api', the 'Observation's+-- | Capture an observation.+data instance Api (ObservationQueue a) r where+  EnqueueObservation :: a -> Api (ObservationQueue a) 'Asynchronous+  StopObservationQueue :: Api (ObservationQueue a) ('Synchronous ())++-- | Observe a 'Server' that implements an 'Observable' 'Api'. The observations -- can be obtained by 'readObservationQueue'. All observations are captured up to -- the queue size limit, such that the first message received will be first message -- returned by 'readObservationQueue'.------ This function captures runtime exceptions and cleans up accordingly.-enqueueObservations-  :: forall o r q a-   . ( SetMember Process (Process q) r-     , Typeable o-     , Show (Observation o)-     , Observable o-     , HasLogging IO r-     , HasLogging IO q-     , Member Interrupts r-     , Lifted IO q-     , HasCallStack-     )-  => SchedulerProxy q-  -> Server o+spawnLinkObserverationQueue+  :: forall o q a+   . (Typeable o, Show o, HasLogging IO q, Lifted IO q, HasCallStack)+  => Server (ObserverRegistry o)   -> Int-  -> Eff (ObservationQueueReader o ': r) a-  -> Eff r a-enqueueObservations px oSvr queueLimit k = withQueue+  -> Eff (ObservationQueueReader o ': InterruptableProcess q) a+  -> Eff (InterruptableProcess q) a+spawnLinkObserverationQueue oSvr queueLimit k = withQueue   queueLimit   (do     ObservationQueue q <- ask @(ObservationQueue o)@@ -144,36 +113,37 @@                 (logPrefix (Proxy @o))                 queueLimit         )-      cbo <- spawnCallbackObserver-        px-        (\_from observation -> do-          liftIO (atomically (writeTBQueue q observation))-          return HandleNextRequest-        )-      logDebug-        (printf "%s started observer process %s"-                (logPrefix (Proxy @o))-                (show cbo)+      cbo <- raise+        (spawnLinkApiServer+          (handleCasts+            (\case+              EnqueueObservation o -> do+                lift (atomically (writeTBQueue q o))+                pure AwaitNext+            )+          )+          stopServerOnInterrupt         )-      registerObserver SchedulerProxy cbo oSvr+      let thisObserver = toObserverFor EnqueueObservation cbo+      registerObserver thisObserver oSvr       res <- k-      forgetObserver SchedulerProxy cbo oSvr-      sendShutdown px (_fromServer cbo) ExitNormally+      forgetObserver thisObserver oSvr+      call cbo StopObservationQueue       logDebug (printf "%s stopped observer process" (logPrefix (Proxy @o)))       return res   )  withQueue-  :: forall a b e len+  :: forall o b e len    . ( HasCallStack-     , Typeable a-     , Show (Observation a)+     , Typeable o+     , Show o      , HasLogging IO e      , Integral len      , Member Interrupts e      )   => len-  -> Eff (ObservationQueueReader a ': e) b+  -> Eff (ObservationQueueReader o ': e) b   -> Eff e b withQueue queueLimit e = do   q   <- liftIO (newTBQueueIO (fromIntegral queueLimit))@@ -182,5 +152,5 @@   rest <- liftIO (atomically (flushTBQueue q))   unless     (null rest)-    (logNotice (logPrefix (Proxy @a) ++ " unread observations: " ++ show rest))+    (logNotice (logPrefix (Proxy @o) ++ " unread observations: " ++ show rest))   either (\em -> logError (show em) >> liftIO (throwIO em)) return res
src/Control/Eff/Concurrent/Api/Request.hs view
@@ -82,6 +82,5 @@   -> reply   -> Eff eff () sendReply origin reply = sendMessage-  SP   (_requestOriginPid origin)   (Reply (Proxy @request) (_requestOriginCallRef origin) $! reply)
src/Control/Eff/Concurrent/Api/Server.hs view
@@ -1,416 +1,471 @@--- | Functions to implement 'Api' __servers__.+-- | Support code to implement 'Api' _server_ processes.+--+-- @since 0.16.0 module Control.Eff.Concurrent.Api.Server-  (-  -- * Api Server-    serve-  , spawnServer-  , spawnServerWithEffects-  -- * Api Callbacks-  , ApiHandler(..)-  , castCallback-  , callCallback-  , terminateCallback-  , apiHandler-  , apiHandlerForever-  , castHandler-  , castHandlerForever-  , callHandler-  , callHandlerForever-  , castAndCallHandler-  , castAndCallHandlerForever-  , ApiServerCmd(..)-  , unhandledCallError-  , unhandledCastError-  , defaultTermination-  -- * Callback Composition-  , Servable(..)-  , ServerCallback(..)-  , requestHandlerSelector-  , terminationHandler+  ( -- * Starting Api Servers+    spawnApiServer+  , spawnLinkApiServer+  , spawnApiServerStateful+  , spawnApiServerEffectful+  , spawnLinkApiServerEffectful+  , apiServerLoop+  -- ** Api Server Callbacks+  , CallbackResult(..)+  , MessageCallback(..)+  -- ** Callback Smart Contructors+  -- *** Calls and Casts (for 'Api's)+  , handleCasts+  , handleCalls+  , handleCastsAndCalls+  , handleCallsDeferred+  -- *** Generic Message Handler+  , handleMessages+  , handleSelectedMessages+  , handleAnyMessages+  , handleProcessDowns+  -- *** Fallback Handler+  , dropUnhandledMessages+  , exitOnUnhandled+  , logUnhandledMessages+  -- ** Api Composition+  , (^:)+  , fallbackHandler+  , ToServerPids(..)+  -- ** Interrupt handler+  , InterruptCallback(..)+  , stopServerOnInterrupt   ) where  import           Control.Eff+import           Control.Eff.Extend+import           Control.Eff.Log+import           Control.Eff.State.Lazy import           Control.Eff.Concurrent.Api import           Control.Eff.Concurrent.Api.Request import           Control.Eff.Concurrent.Process-import           Control.Eff.Exception-import           Control.Eff.Log-import           Control.Lens+import           Control.Monad                  ( (>=>) ) import           Data.Proxy-import           Data.Typeable                  ( Typeable-                                                , typeRep-                                                ) import           Data.Dynamic import           Control.Applicative-import           Data.Kind import           GHC.Stack-import           Data.Maybe-import           GHC.Generics import           Control.DeepSeq+import           Data.Kind+import           Data.Foldable import           Data.Default ---- | A record of callbacks, handling requests sent to a /server/ 'Process', all--- belonging to a specific 'Api' family instance.--- The values of this type can be 'serve'ed or combined via 'Servable' or--- 'ServerCallback's.-data ApiHandler api eff where-  ApiHandler ::-     { -- | A cast will not return a result directly. This is used for async-       -- methods. This returns an 'ApiServerCmd' to the server loop.-       _castCallback-         :: Maybe (Api api 'Asynchronous -> Eff eff ApiServerCmd)-      -- | A call is a blocking operation, the caller is blocked until this-      -- handler calls the reply continuation.-      -- This returns an 'ApiServerCmd' to the server loop.-     , _callCallback-         :: forall reply . Maybe (Api api ('Synchronous reply) -> (reply -> Eff eff ()) -> Eff eff ApiServerCmd)-     -- | This callback is called with @Nothing@ if one of these things happen:-     ---     --  * the process exits-     --  * '_callCallback' or '_castCallback' return 'StopApiServer'-     ---     -- If the process exist peacefully the parameter is 'NotServerCallbacking',-     -- otherwise @Just "error message..."@ if the process exits with an-     -- error.-     ---     -- The default behavior is defined in 'defaultTermination'.-     , _terminateCallback-         :: Maybe (ExitReason 'Recoverable -> Eff eff ())-     } -> ApiHandler api eff+-- | /Serve/ an 'Api' in a newly spawned process.+--+-- @since 0.13.2+spawnApiServer+  :: forall api eff+   . (ToServerPids api, HasCallStack)+  => MessageCallback api (InterruptableProcess eff)+  -> InterruptCallback (ConsProcess eff)+  -> Eff (InterruptableProcess eff) (ServerPids api)+spawnApiServer scb (InterruptCallback icb) = toServerPids (Proxy @api)+  <$> spawn (apiServerLoop scb (InterruptCallback (raise . icb))) +-- | /Serve/ an 'Api' in a newly spawned -and linked - process.+--+-- @since 0.14.2+spawnLinkApiServer+  :: forall api eff+   . (ToServerPids api, HasCallStack)+  => MessageCallback api (InterruptableProcess eff)+  -> InterruptCallback (ConsProcess eff)+  -> Eff (InterruptableProcess eff) (ServerPids api)+spawnLinkApiServer scb (InterruptCallback icb) = toServerPids (Proxy @api)+  <$> spawnLink (apiServerLoop scb (InterruptCallback (raise . icb))) -instance Default (ApiHandler api eff) where-  def = ApiHandler { _castCallback = def-                   , _callCallback = def-                   , _terminateCallback = def-                   }+-- | /Server/ an 'Api' in a newly spawned process; the callbacks have access+-- to some state initialed by the function in the first parameter.+--+-- @since 0.13.2+spawnApiServerStateful+  :: forall api eff state+   . (HasCallStack, ToServerPids api)+  => Eff (InterruptableProcess eff) state+  -> MessageCallback api (State state ': InterruptableProcess eff)+  -> InterruptCallback (State state ': ConsProcess eff)+  -> Eff (InterruptableProcess eff) (ServerPids api)+spawnApiServerStateful initEffect (MessageCallback sel cb) (InterruptCallback intCb)+  = fmap (toServerPids (Proxy @api)) $ spawnRaw $ do+    state <- provideInterruptsShutdown initEffect+    evalState state $ receiveSelectedLoop sel $ \msg -> case msg of+      Left  m -> invokeIntCb m+      Right m -> do+        s <- get+        r <- raise (provideInterrupts (evalState s (cb m)))+        case r of+          Left  i              -> invokeIntCb i+          Right (StopServer i) -> invokeIntCb i+          Right AwaitNext      -> return Nothing+ where+  invokeIntCb j = do+    l <- intCb j+    case l of+      AwaitNext                  -> return Nothing+      StopServer ProcessFinished -> return (Just ())+      StopServer k               -> exitBecause (NotRecovered k) --- | Create an 'ApiHandler' with a '_castCallback', a '_callCallback'  and---  a '_terminateCallback' implementation.-apiHandler-  :: (Api api 'Asynchronous -> Eff e ApiServerCmd)-  -> (  forall r-      . Api api ( 'Synchronous r)-     -> (r -> Eff e ())-     -> Eff e ApiServerCmd+-- | /Server/ an 'Api' in a newly spawned process; The caller provides an+-- effect handler for arbitrary effects used by the server callbacks.+--+-- @since 0.13.2+spawnApiServerEffectful+  :: forall api eff serverEff+   . ( HasCallStack+     , ToServerPids api+     , Member Interrupts serverEff+     , SetMember Process (Process eff) serverEff      )-  -> (ExitReason 'Recoverable -> Eff e ())-  -> ApiHandler api e-apiHandler c d e = ApiHandler-  { _castCallback      = Just c-  , _callCallback      = Just d-  , _terminateCallback = Just e-  }+  => (forall b . Eff serverEff b -> Eff (InterruptableProcess eff) b)+  -> MessageCallback api serverEff+  -> InterruptCallback serverEff+  -> Eff (InterruptableProcess eff) (ServerPids api)+spawnApiServerEffectful handleServerInteralEffects scb icb =+  toServerPids (Proxy @api)+    <$> spawn (handleServerInteralEffects (apiServerLoop scb icb)) --- | Like 'apiHandler' but the server will loop until an error is raised or--- the process exits.--- The callback actions won't decide wether to stop the--- server or not, instead the 'ApiServerCmd' 'HandleNextRequest' is used.-apiHandlerForever-  :: (Api api 'Asynchronous -> Eff e ())-  -> (forall r . Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ())-  -> (ExitReason 'Recoverable -> Eff e ())-  -> ApiHandler api e-apiHandlerForever c d = apiHandler-  (\someCast -> c someCast >> return HandleNextRequest)-  (\someCall k -> d someCall k >> return HandleNextRequest) --- | Create an 'ApiHandler' with only a '_castCallback' implementation.-castHandler-  :: (Api api 'Asynchronous -> Eff eff ApiServerCmd) -> ApiHandler api eff-castHandler c = def { _castCallback = Just c }---- | Like 'castHandler' but the server will loop until an error is raised or--- the process exits. See 'apiHandlerForver'.-castHandlerForever-  :: (Api api 'Asynchronous -> Eff eff ()) -> ApiHandler api eff-castHandlerForever c =-  castHandler (\someCast -> c someCast >> return HandleNextRequest)---- | Create an 'ApiHandler' with only a '_callCallback' implementation.-callHandler-  :: (  forall r-      . Api api ( 'Synchronous r)-     -> (r -> Eff e ())-     -> Eff e ApiServerCmd+-- | /Server/ an 'Api' in a newly spawned process; The caller provides an+-- effect handler for arbitrary effects used by the server callbacks.+-- Links to the calling process like 'linkProcess' would.+--+-- @since 0.14.2+spawnLinkApiServerEffectful+  :: forall api eff serverEff+   . ( HasCallStack+     , ToServerPids api+     , Member Interrupts serverEff+     , SetMember Process (Process eff) serverEff      )-  -> ApiHandler api e-callHandler c = def { _callCallback = Just c }---- | Like 'callHandler' but the server will loop until an error is raised or--- the process exits. See 'apiHandlerForver'.-callHandlerForever-  :: (forall r . Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ())-  -> ApiHandler api e-callHandlerForever d =-  callHandler (\someCall k -> d someCall k >> return HandleNextRequest)+  => (forall b . Eff serverEff b -> Eff (InterruptableProcess eff) b)+  -> MessageCallback api serverEff+  -> InterruptCallback serverEff+  -> Eff (InterruptableProcess eff) (ServerPids api)+spawnLinkApiServerEffectful handleServerInteralEffects scb icb =+  toServerPids (Proxy @api)+    <$> spawnLink (handleServerInteralEffects (apiServerLoop scb icb)) --- | Create an 'ApiHandler' with only a '_castCallback' and '_callCallback' implementation.-castAndCallHandler-  :: (Api api 'Asynchronous -> Eff e ApiServerCmd)-  -> (  forall r-      . Api api ( 'Synchronous r)-     -> (r -> Eff e ())-     -> Eff e ApiServerCmd+-- | Receive loop for 'Api' 'call's. This starts a receive loop for+-- a 'MessageCallback'. It is used behind the scenes by 'spawnLinkApiServerEffectful'+-- and 'spawnApiServerEffectful'.+--+-- @since 0.14.2+apiServerLoop+  :: forall api eff serverEff+   . ( HasCallStack+     , ToServerPids api+     , Member Interrupts serverEff+     , SetMember Process (Process eff) serverEff      )-  -> ApiHandler api e-castAndCallHandler c d = def { _castCallback = Just c, _callCallback = Just d }---- | Like 'castAndCallHandler' but the server will loop until an error is raised or--- the process exits. See 'apiHandlerForver'.-castAndCallHandlerForever-  :: (Api api 'Asynchronous -> Eff e ())-  -> (forall r . Api api ( 'Synchronous r) -> (r -> Eff e ()) -> Eff e ())-  -> ApiHandler api e-castAndCallHandlerForever c d = castAndCallHandler-  (\someCast -> c someCast >> return HandleNextRequest)-  (\someCall k -> d someCall k >> return HandleNextRequest)+  => MessageCallback api serverEff+  -> InterruptCallback serverEff+  -> Eff serverEff ()+apiServerLoop (MessageCallback sel cb) (InterruptCallback intCb) =+  receiveSelectedLoop+    sel+    (   either (fmap Left . intCb) (fmap Right . tryUninterrupted . cb)+    >=> handleCallbackResult+    )+ where+  handleCallbackResult+    :: Either CallbackResult (Either InterruptReason CallbackResult)+    -> Eff serverEff (Maybe ())+  handleCallbackResult (Left AwaitNext) = return Nothing+  handleCallbackResult (Left (StopServer r)) = exitBecause (NotRecovered r)+  handleCallbackResult (Right (Right AwaitNext)) = return Nothing+  handleCallbackResult (Right (Right (StopServer r))) =+    intCb r >>= handleCallbackResult . Left+  handleCallbackResult (Right (Left r)) =+    intCb r >>= handleCallbackResult . Left  -- | A command to the server loop started e.g. by 'server' or 'spawnServerWithEffects'. -- Typically returned by an 'ApiHandler' member to indicate if the server -- should continue or stop.-data ApiServerCmd where+--+-- @since 0.13.2+data CallbackResult where   -- | Tell the server to keep the server loop running-  HandleNextRequest  :: ApiServerCmd+  AwaitNext :: CallbackResult   -- | Tell the server to exit, this will make 'serve' stop handling requests without   -- exitting the process. '_terminateCallback' will be invoked with the given   -- optional reason.-  StopApiServer :: ExitReason 'Recoverable -> ApiServerCmd-  --  SendReply :: reply -> ApiServerCmd () -> ApiServerCmd (reply -> Eff eff ())-  deriving (Show, Typeable, Generic)+  StopServer :: InterruptReason -> CallbackResult+  --  SendReply :: reply -> CallbackResult () -> CallbackResult (reply -> Eff eff ())+  deriving ( Typeable ) -instance NFData ApiServerCmd -makeLenses ''ApiHandler---- | Building block for composition of 'ApiHandler'.--- A wrapper for 'ApiHandler'. Use this to combine 'ApiHandler', allowing a--- process to implement several 'Api' instances. The termination will be evenly--- propagated.--- Create this via e.g. 'Servable' instances--- To serve multiple apis use '<>' to combine server callbacks, e.g.+-- | An existential wrapper around  a 'MessageSelector' and a function that+-- handles the selected message. The @api@ type parameter is a phantom type. ----- @@@--- let f = apiHandlerServerCallback px $ ApiHandler ...---     g = apiHandlerServerCallback px $ ApiHandler ...---     h = f <> g--- in serve px h--- @@@+-- The return value if the handler function is a 'CallbackResult'. ---data ServerCallback eff =-  ServerCallback { _requestHandlerSelector :: MessageSelector (Eff eff ApiServerCmd)-                 , _terminationHandler :: ExitReason 'Recoverable -> Eff eff ()-                 }--makeLenses ''ServerCallback+-- @since 0.13.2+data MessageCallback api eff where+   MessageCallback :: MessageSelector a -> (a -> Eff eff CallbackResult) -> MessageCallback api eff -instance Semigroup (ServerCallback eff) where-  l <> r = l & requestHandlerSelector .~-                  selectDynamicMessageLazy (\x ->-                    runMessageSelector (view requestHandlerSelector l) x <|>-                    runMessageSelector (view requestHandlerSelector r) x)-             & terminationHandler .~-                  (\reason ->-                      do (l^.terminationHandler) reason-                         (r^.terminationHandler) reason)+instance Semigroup (MessageCallback api eff) where+  (MessageCallback selL runL) <> (MessageCallback selR runR) =+    MessageCallback (Left <$> selL <|> Right <$> selR) (either runL runR) -instance Monoid (ServerCallback eff) where+instance Monoid (MessageCallback api eff) where   mappend = (<>)-  mempty = ServerCallback-              { _requestHandlerSelector = selectDynamicMessageLazy (const Nothing)-              , _terminationHandler = const (return ())-              }+  mempty  = MessageCallback selectAnyMessageLazy (const (pure AwaitNext)) --- | Helper type class to allow composition of 'ApiHandler'.-class Servable a where-  -- | The effect of the callbacks-  type ServerEff a :: [Type -> Type]-  -- | The is used to let the spawn function return multiple 'Server' 'ProcessId's-  -- in a type safe way, e.g. for a tuple instance of this class-  -- @(Server a, Server b)@-  type ServerPids a-  -- | The is used to let the spawn function return multiple 'Server' 'ProcessId's-  -- in a type safe way.-  toServerPids :: proxy a -> ProcessId -> ServerPids a-  -- | Convert the value to a 'ServerCallback'-  toServerCallback-    :: (Member Interrupts (ServerEff a), SetMember Process (Process effScheduler) (ServerEff a))-    => SchedulerProxy effScheduler -> a -> ServerCallback (ServerEff a)+instance Default (MessageCallback api eff) where+  def = mempty -instance Servable (ServerCallback eff)  where-  type ServerEff (ServerCallback eff) = eff-  type ServerPids (ServerCallback eff) = ProcessId-  toServerCallback  = const id-  toServerPids = const id+-- | A smart constructor for 'MessageCallback's+--+-- @since 0.13.2+handleMessages+  :: forall eff a+   . (HasCallStack, NFData a, Typeable a)+  => (a -> Eff eff CallbackResult)+  -> MessageCallback '[] eff+handleMessages = MessageCallback selectMessage -instance Typeable a => Servable (ApiHandler a eff)  where-  type ServerEff (ApiHandler a eff) = eff-  type ServerPids (ApiHandler a eff) = Server a-  toServerCallback  = apiHandlerServerCallback-  toServerPids _ = asServer+-- | A smart constructor for 'MessageCallback's+--+-- @since 0.13.2+handleSelectedMessages+  :: forall eff a+   . HasCallStack+  => MessageSelector a+  -> (a -> Eff eff CallbackResult)+  -> MessageCallback '[] eff+handleSelectedMessages = MessageCallback -instance (ServerEff a ~ ServerEff b, Servable a, Servable b) => Servable (a, b) where-  type ServerPids (a, b) = (ServerPids a, ServerPids b)-  type ServerEff (a, b) = ServerEff a-  toServerCallback px (a, b) = toServerCallback px a <> toServerCallback px b-  toServerPids _ pid =-    ( toServerPids (Proxy :: Proxy a) pid-    , toServerPids (Proxy :: Proxy b) pid-    )+-- | A smart constructor for 'MessageCallback's+--+-- @since 0.13.2+handleAnyMessages+  :: forall eff+   . HasCallStack+  => (Dynamic -> Eff eff CallbackResult)+  -> MessageCallback '[] eff+handleAnyMessages = MessageCallback selectAnyMessageLazy --- | Receive and process incoming requests until the process exits.-serve-  :: forall a effScheduler-   . ( Servable a-     , SetMember Process (Process effScheduler) (ServerEff a)-     , Member Interrupts (ServerEff a)-     , HasCallStack-     )-  => SchedulerProxy effScheduler-  -> a-  -> Eff (ServerEff a) ()-serve px a =-  let serverCb = toServerCallback px a-      stopServer reason = do-        (serverCb ^. terminationHandler) reason-        return (Just ())-  in  receiveSelectedLoop px (serverCb ^. requestHandlerSelector) $ \case-        Left  reason   -> stopServer reason-        Right handleIt -> handleIt >>= \case-          HandleNextRequest    -> return Nothing-          StopApiServer reason -> stopServer reason+-- | A smart constructor for 'MessageCallback's+--+-- @since 0.13.2+handleCasts+  :: forall api eff+   . (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous))+  => (Api api 'Asynchronous -> Eff eff CallbackResult)+  -> MessageCallback api eff+handleCasts h = MessageCallback+  (selectMessageWithLazy+    (\case+      cr@(Cast _ :: Request api) -> Just cr+      _callReq                   -> Nothing+    )+  )+  (\(Cast req :: Request api) -> h req) --- | Spawn a new process, that will receive and process incoming requests--- until the process exits.-spawnServer-  :: forall a effScheduler eff-   . ( Servable a-     , ServerEff a ~ (InterruptableProcess effScheduler)+-- | A smart constructor for 'MessageCallback's+--+-- > handleCalls SP+-- >   (\ (RentBook bookId customerId) runCall ->+-- >      runCall $ do+-- >          rentalIdE <- rentBook bookId customerId+-- >          case rentalIdE of+-- >            -- on fail we just don't send a reply, let the caller run into+-- >            -- timeout+-- >            Left err -> return (Nothing, AwaitNext)+-- >            Right rentalId -> return (Just rentalId, AwaitNext))+--+-- @since 0.13.2+handleCalls+  :: forall api eff effScheduler+   . ( HasCallStack+     , Typeable api      , SetMember Process (Process effScheduler) eff      , Member Interrupts eff-     , HasCallStack      )-  => SchedulerProxy effScheduler-  -> a-  -> Eff eff (ServerPids a)-spawnServer px a = spawnServerWithEffects px a id---- | Spawn a new process, that will receive and process incoming requests--- until the process exits. Also handle all internal effects.-spawnServerWithEffects-  :: forall a effScheduler eff-   . ( Servable a-     , SetMember Process (Process effScheduler) (ServerEff a)-     , SetMember Process (Process effScheduler) eff-     , Member Interrupts eff-     , Member Interrupts (ServerEff a)-     , HasCallStack-     )-  => SchedulerProxy effScheduler-  -> a-  -> (  Eff (ServerEff a) ()-     -> Eff (InterruptableProcess effScheduler) ()+  => (  forall secret reply+      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))+     => Api api ( 'Synchronous reply)+     -> (Eff eff (Maybe reply, CallbackResult) -> secret)+     -> secret      )-  -> Eff eff (ServerPids a)-spawnServerWithEffects px a handleEff = do-  pid <- spawn (handleEff (serve px a))-  return (toServerPids (Proxy @a) pid)+  -> MessageCallback api eff+handleCalls h = MessageCallback+  (selectMessageWithLazy+    (\case+      (Cast _ :: Request api) -> Nothing+      callReq                 -> Just callReq+    )+  )+  (\(Call callRef fromPid req :: Request api) -> h+    req+    (\resAction -> do+      (mReply, cbResult) <- resAction+      traverse_ (sendReply (mkRequestOrigin req fromPid callRef)) mReply+      return cbResult+    )+  ) --- | Wrap an 'ApiHandler' into a composable 'ServerCallback' value.-apiHandlerServerCallback-  :: forall eff effScheduler api++-- | A smart constructor for 'MessageCallback's+--+-- @since 0.13.2+handleCastsAndCalls+  :: forall api eff effScheduler    . ( HasCallStack      , Typeable api+     , Typeable (Api api 'Asynchronous)      , SetMember Process (Process effScheduler) eff      , Member Interrupts eff      )-  => SchedulerProxy effScheduler-  -> ApiHandler api eff-  -> ServerCallback eff-apiHandlerServerCallback px handlers = mempty-  { _requestHandlerSelector = selectHandlerMethod px handlers-  , _terminationHandler     = fromMaybe (const (return ()))-                                        (_terminateCallback handlers)-  }+  => (Api api 'Asynchronous -> Eff eff CallbackResult)+  -> (  forall secret reply+      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))+     => Api api ( 'Synchronous reply)+     -> (Eff eff (Maybe reply, CallbackResult) -> secret)+     -> secret+     )+  -> MessageCallback api eff+handleCastsAndCalls onCast onCall = handleCalls onCall <> handleCasts onCast --- | Try to parse an incoming message to an API request, and apply either--- the 'handleCall' method or the 'handleCast' method to it.-selectHandlerMethod-  :: forall eff effScheduler api++-- | A variation of 'handleCalls' that allows to defer a reply to a call.+--+-- @since 0.14.2+handleCallsDeferred+  :: forall api eff effScheduler    . ( HasCallStack      , Typeable api      , SetMember Process (Process effScheduler) eff      , Member Interrupts eff      )-  => SchedulerProxy effScheduler-  -> ApiHandler api eff-  -> MessageSelector (Eff eff ApiServerCmd)-selectHandlerMethod px handlers =-  selectDynamicMessageLazy (fmap (applyHandlerMethod px handlers) . fromDynamic)---- | Apply either the '_callCallback', '_castCallback' or the '_terminateCallback'--- callback to an incoming request.-applyHandlerMethod-  :: forall eff effScheduler api-   . ( Typeable api-     , SetMember Process (Process effScheduler) eff-     , Member Interrupts eff-     , HasCallStack+  => (  forall reply+      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))+     => RequestOrigin (Api api ( 'Synchronous reply))+     -> Api api ( 'Synchronous reply)+     -> Eff eff CallbackResult      )-  => SchedulerProxy effScheduler-  -> ApiHandler api eff-  -> Request api-  -> Eff eff ApiServerCmd-applyHandlerMethod px handlers (Cast request) =-  fromMaybe (unhandledCastError px) (_castCallback handlers) request-applyHandlerMethod px handlers (Call callRef fromPid request) = fromMaybe-  (unhandledCallError px)-  (_callCallback handlers)-  request-  (sendReply (mkRequestOrigin request fromPid callRef))+  -> MessageCallback api eff+handleCallsDeferred h = MessageCallback+  (selectMessageWithLazy+    (\case+      (Cast _ :: Request api) -> Nothing+      callReq                 -> Just callReq+    )+  )+  (\(Call callRef fromPid req :: Request api) ->+    h (RequestOrigin fromPid callRef) req+  ) --- | A default handler to use in '_callCallback' in 'ApiHandler'. It will call--- 'raiseError' with a nice error message.-unhandledCallError-  :: forall p x r q-   . ( Typeable p-     , HasCallStack-     , SetMember Process (Process q) r-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> Api p ( 'Synchronous x)-  -> (x -> Eff r ())-  -> Eff r ApiServerCmd-unhandledCallError _px _api _ = throwError-  (ProcessError ("unhandled call on api: " ++ show (typeRep (Proxy @p))))+type family ResponseType request where+  ResponseType (Api a ('Synchronous r)) = r --- | A default handler to use in '_castCallback' in 'ApiHandler'. It will call--- 'raiseError' with a nice error message.-unhandledCastError-  :: forall p r q-   . ( Typeable p-     , HasCallStack-     , SetMember Process (Process q) r-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> Api p 'Asynchronous-  -> Eff r ApiServerCmd-unhandledCastError _px _api = throwError-  (ProcessError ("unhandled cast on api: " ++ show (typeRep (Proxy @p)))) --- | Either do nothing, if the error message is @Nothing@,--- or call 'exitWithError' with the error message.-defaultTermination-  :: forall q r-   . ( HasCallStack-     , SetMember Process (Process q) r-     , Member (Logs LogMessage) r-     )-  => SchedulerProxy q-  -> ExitReason 'Recoverable-  -> Eff r ()-defaultTermination _px r = logNotice ("server process terminating " ++ show r)+-- | A smart constructor for 'MessageCallback's+--+-- @since 0.13.2+handleProcessDowns+  :: forall eff+   . HasCallStack+  => (MonitorReference -> Eff eff CallbackResult)+  -> MessageCallback '[] eff+handleProcessDowns k = MessageCallback selectMessage (k . downReference)++-- | Compose two 'Api's to a type-leve pair of them.+--+-- > handleCalls api1calls ^: handleCalls api2calls ^:+--+-- @since 0.13.2+(^:)+  :: forall (api1 :: Type) (apis2 :: [Type]) eff+   . HasCallStack+  => MessageCallback api1 eff+  -> MessageCallback apis2 eff+  -> MessageCallback (api1 ': apis2) eff+(MessageCallback selL runL) ^: (MessageCallback selR runR) =+  MessageCallback (Left <$> selL <|> Right <$> selR) (either runL runR)++infixr 5 ^:++-- | Make a fallback handler, i.e. a handler to which no other can be composed+-- to from the right.+--+-- @since 0.13.2+fallbackHandler+  :: forall api eff+   . HasCallStack+  => MessageCallback api eff+  -> MessageCallback '[] eff+fallbackHandler (MessageCallback s r) = MessageCallback s r++-- | A 'fallbackHandler' that drops the left-over messages.+--+-- @since 0.13.2+dropUnhandledMessages :: forall eff . HasCallStack => MessageCallback '[] eff+dropUnhandledMessages =+  MessageCallback selectAnyMessageLazy (const (return AwaitNext))++-- | A 'fallbackHandler' that terminates if there are unhandled messages.+--+-- @since 0.13.2+exitOnUnhandled :: forall eff . HasCallStack => MessageCallback '[] eff+exitOnUnhandled = MessageCallback selectAnyMessageLazy $ \msg ->+  return (StopServer (ProcessError ("unhandled message " ++ show msg)))++-- | A 'fallbackHandler' that drops the left-over messages.+--+-- @since 0.13.2+logUnhandledMessages+  :: forall eff+   . (Member (Logs LogMessage) eff, HasCallStack)+  => MessageCallback '[] eff+logUnhandledMessages = MessageCallback selectAnyMessageLazy $ \msg -> do+  logWarning ("ignoring unhandled message " ++ show msg)+  return AwaitNext++-- | Helper type class for the return values of 'spawnApiServer' et al.+--+-- @since 0.13.2+class ToServerPids (t :: k) where+  type ServerPids t+  toServerPids :: proxy t -> ProcessId -> ServerPids t++instance ToServerPids '[] where+  type ServerPids '[] = ProcessId+  toServerPids _ = id++instance+  forall (api1 :: Type) (api2 :: [Type])+  . (ToServerPids api1, ToServerPids api2)+  => ToServerPids (api1 ': api2) where+  type ServerPids (api1 ': api2) = (ServerPids api1, ServerPids api2)+  toServerPids _ p =+    (toServerPids (Proxy @api1) p, toServerPids (Proxy @api2) p)++instance+  forall (api1 :: Type)+  . (ToServerPids api1)+  => ToServerPids api1 where+  type ServerPids api1 = Server api1+  toServerPids _ = asServer++-- | Just a wrapper around a function that will be applied to the result of+-- a 'MessageCallback's 'StopServer' clause, or an 'InterruptReason' caught during+-- the execution of @receive@ or a 'MessageCallback'+--+-- @since 0.13.2+data InterruptCallback eff where+   InterruptCallback ::+     (InterruptReason -> Eff eff CallbackResult) -> InterruptCallback eff++instance Default (InterruptCallback eff) where+  def = stopServerOnInterrupt++-- | A smart constructor for 'InterruptCallback's+--+-- @since 0.13.2+stopServerOnInterrupt :: forall eff . HasCallStack => InterruptCallback eff+stopServerOnInterrupt = InterruptCallback (pure . StopServer)
− src/Control/Eff/Concurrent/Api/Server2.hs
@@ -1,504 +0,0 @@--- | Experimental new 'Api' server handler.------ @since 0.13.2-module Control.Eff.Concurrent.Api.Server2-  ( -- * Starting Api Servers-    spawnApiServer-  , spawnLinkApiServer-  , spawnApiServerStateful-  , spawnApiServerEffectful-  , spawnLinkApiServerEffectful-  , apiServerLoop-  -- ** Api Server Callbacks-  , CallbackResult(..)-  , MessageCallback(..)-  -- ** Callback Smart Contructors-  -- *** Calls and Casts (for 'Api's)-  , handleCasts-  , handleCalls-  , handleCastsAndCalls-  , handleCallsDeferred-  -- *** Generic Message Handler-  , handleMessages-  , handleSelectedMessages-  , handleAnyMessages-  , handleProcessDowns-  -- *** Fallback Handler-  , dropUnhandledMessages-  , exitOnUnhandled-  , logUnhandledMessages-  -- ** Api Composition-  , (^:)-  , fallbackHandler-  , ToServerPids(..)-  -- ** Interrupt handler-  , InterruptCallback(..)-  , stopServerOnInterrupt-  -- * Observers-  , handleObservations-  , Observing()-  )-where--import           Control.Eff-import           Control.Eff.Extend-import           Control.Eff.Log-import           Control.Eff.State.Lazy-import           Control.Eff.Concurrent.Api-import           Control.Eff.Concurrent.Api.Observer-import           Control.Eff.Concurrent.Api.Request-import           Control.Eff.Concurrent.Process-import           Control.Monad                  ( (>=>) )-import           Data.Proxy-import           Data.Dynamic-import           Control.Applicative-import           GHC.Stack-import           Control.DeepSeq-import           Data.Kind-import           Data.Foldable-import           Data.Default---- | /Serve/ an 'Api' in a newly spawned process.------ @since 0.13.2-spawnApiServer-  :: forall api eff-   . (ToServerPids api, HasCallStack)-  => MessageCallback api (InterruptableProcess eff)-  -> InterruptCallback (ConsProcess eff)-  -> Eff (InterruptableProcess eff) (ServerPids api)-spawnApiServer scb (InterruptCallback icb) = toServerPids (Proxy @api)-  <$> spawn (apiServerLoop scb (InterruptCallback (raise . icb)))---- | /Serve/ an 'Api' in a newly spawned -and linked - process.------ @since 0.14.2-spawnLinkApiServer-  :: forall api eff-   . (ToServerPids api, HasCallStack)-  => MessageCallback api (InterruptableProcess eff)-  -> InterruptCallback (ConsProcess eff)-  -> Eff (InterruptableProcess eff) (ServerPids api)-spawnLinkApiServer scb (InterruptCallback icb) = toServerPids (Proxy @api)-  <$> spawnLink (apiServerLoop scb (InterruptCallback (raise . icb)))---- | /Server/ an 'Api' in a newly spawned process; the callbacks have access--- to some state initialed by the function in the first parameter.------ @since 0.13.2-spawnApiServerStateful-  :: forall api eff state-   . (HasCallStack, ToServerPids api)-  => Eff (InterruptableProcess eff) state-  -> MessageCallback api (State state ': InterruptableProcess eff)-  -> InterruptCallback (State state ': ConsProcess eff)-  -> Eff (InterruptableProcess eff) (ServerPids api)-spawnApiServerStateful initEffect (MessageCallback sel cb) (InterruptCallback intCb)-  = fmap (toServerPids (Proxy @api)) $ spawnRaw $ do-    state <- provideInterruptsShutdown initEffect-    evalState state $ receiveSelectedLoop (SP @eff) sel $ \msg -> case msg of-      Left  m -> invokeIntCb m-      Right m -> do-        s <- get-        r <- raise (provideInterrupts (evalState s (cb m)))-        case r of-          Left  i              -> invokeIntCb i-          Right (StopServer i) -> invokeIntCb i-          Right AwaitNext      -> return Nothing- where-  invokeIntCb j = do-    l <- intCb j-    case l of-      AwaitNext                  -> return Nothing-      StopServer ProcessFinished -> return (Just ())-      StopServer k               -> exitBecause SP (NotRecovered k)---- | /Server/ an 'Api' in a newly spawned process; The caller provides an--- effect handler for arbitrary effects used by the server callbacks.------ @since 0.13.2-spawnApiServerEffectful-  :: forall api eff serverEff-   . ( HasCallStack-     , ToServerPids api-     , Member Interrupts serverEff-     , SetMember Process (Process eff) serverEff-     )-  => (forall b . Eff serverEff b -> Eff (InterruptableProcess eff) b)-  -> MessageCallback api serverEff-  -> InterruptCallback serverEff-  -> Eff (InterruptableProcess eff) (ServerPids api)-spawnApiServerEffectful handleServerInteralEffects scb icb =-  toServerPids (Proxy @api)-    <$> spawn (handleServerInteralEffects (apiServerLoop scb icb))----- | /Server/ an 'Api' in a newly spawned process; The caller provides an--- effect handler for arbitrary effects used by the server callbacks.--- Links to the calling process like 'linkProcess' would.------ @since 0.14.2-spawnLinkApiServerEffectful-  :: forall api eff serverEff-   . ( HasCallStack-     , ToServerPids api-     , Member Interrupts serverEff-     , SetMember Process (Process eff) serverEff-     )-  => (forall b . Eff serverEff b -> Eff (InterruptableProcess eff) b)-  -> MessageCallback api serverEff-  -> InterruptCallback serverEff-  -> Eff (InterruptableProcess eff) (ServerPids api)-spawnLinkApiServerEffectful handleServerInteralEffects scb icb =-  toServerPids (Proxy @api)-    <$> spawnLink (handleServerInteralEffects (apiServerLoop scb icb))---- | Receive loop for 'Api' 'call's. This starts a receive loop for--- a 'MessageCallback'. It is used behind the scenes by 'spawnLinkApiServerEffectful'--- and 'spawnApiServerEffectful'.------ @since 0.14.2-apiServerLoop-  :: forall api eff serverEff-   . ( HasCallStack-     , ToServerPids api-     , Member Interrupts serverEff-     , SetMember Process (Process eff) serverEff-     )-  => MessageCallback api serverEff-  -> InterruptCallback serverEff-  -> Eff serverEff ()-apiServerLoop (MessageCallback sel cb) (InterruptCallback intCb) =-  receiveSelectedLoop-    (SP @eff)-    sel-    (   either (fmap Left . intCb) (fmap Right . tryUninterrupted . cb)-    >=> handleCallbackResult-    )- where-  handleCallbackResult-    :: Either CallbackResult (Either InterruptReason CallbackResult)-    -> Eff serverEff (Maybe ())-  handleCallbackResult (Left AwaitNext) = return Nothing-  handleCallbackResult (Left (StopServer r)) = exitBecause SP (NotRecovered r)-  handleCallbackResult (Right (Right AwaitNext)) = return Nothing-  handleCallbackResult (Right (Right (StopServer r))) =-    intCb r >>= handleCallbackResult . Left-  handleCallbackResult (Right (Left r)) =-    intCb r >>= handleCallbackResult . Left---- | A command to the server loop started e.g. by 'server' or 'spawnServerWithEffects'.--- Typically returned by an 'ApiHandler' member to indicate if the server--- should continue or stop.------ @since 0.13.2-data CallbackResult where-  -- | Tell the server to keep the server loop running-  AwaitNext :: CallbackResult-  -- | Tell the server to exit, this will make 'serve' stop handling requests without-  -- exitting the process. '_terminateCallback' will be invoked with the given-  -- optional reason.-  StopServer :: InterruptReason -> CallbackResult-  --  SendReply :: reply -> CallbackResult () -> CallbackResult (reply -> Eff eff ())-  deriving ( Typeable )----- | An existential wrapper around  a 'MessageSelector' and a function that--- handles the selected message. The @api@ type parameter is a phantom type.------ The return value if the handler function is a 'CallbackResult'.------ @since 0.13.2-data MessageCallback api eff where-   MessageCallback :: MessageSelector a -> (a -> Eff eff CallbackResult) -> MessageCallback api eff--instance Semigroup (MessageCallback api eff) where- (MessageCallback selL runL) <> (MessageCallback selR runR) =-    MessageCallback (Left <$> selL <|> Right <$> selR) (either runL runR)--instance Monoid (MessageCallback api eff) where-  mappend = (<>)-  mempty = MessageCallback selectAnyMessageLazy (const (pure AwaitNext))--instance Default (MessageCallback api eff) where-  def = mempty---- | A smart constructor for 'MessageCallback's------ @since 0.13.2-handleMessages-  :: forall eff a-   . (HasCallStack, NFData a, Typeable a)-  => (a -> Eff eff CallbackResult)-  -> MessageCallback '[] eff-handleMessages = MessageCallback selectMessage---- | A smart constructor for 'MessageCallback's------ @since 0.13.2-handleSelectedMessages-  :: forall eff a-   . HasCallStack-  => MessageSelector a-  -> (a -> Eff eff CallbackResult)-  -> MessageCallback '[] eff-handleSelectedMessages = MessageCallback---- | A smart constructor for 'MessageCallback's------ @since 0.13.2-handleAnyMessages-  :: forall eff-   . HasCallStack-  => (Dynamic -> Eff eff CallbackResult)-  -> MessageCallback '[] eff-handleAnyMessages = MessageCallback selectAnyMessageLazy---- | A smart constructor for 'MessageCallback's------ @since 0.13.2-handleCasts-  :: forall api eff-   . (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous))-  => (Api api 'Asynchronous -> Eff eff CallbackResult)-  -> MessageCallback api eff-handleCasts h = MessageCallback-  (selectMessageWithLazy-    (\case-      cr@(Cast _ :: Request api) -> Just cr-      _callReq                   -> Nothing-    )-  )-  (\(Cast req :: Request api) -> h req)---- | A smart constructor for 'MessageCallback's------ > handleCalls SP--- >   (\ (RentBook bookId customerId) runCall ->--- >      runCall $ do--- >          rentalIdE <- rentBook bookId customerId--- >          case rentalIdE of--- >            -- on fail we just don't send a reply, let the caller run into--- >            -- timeout--- >            Left err -> return (Nothing, AwaitNext)--- >            Right rentalId -> return (Just rentalId, AwaitNext))------ @since 0.13.2-handleCalls-  :: forall api eff effScheduler-   . ( HasCallStack-     , Typeable api-     , SetMember Process (Process effScheduler) eff-     , Member Interrupts eff-     )-  => SchedulerProxy effScheduler-  -> (  forall secret reply-      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))-     => Api api ( 'Synchronous reply)-     -> (Eff eff (Maybe reply, CallbackResult) -> secret)-     -> secret-     )-  -> MessageCallback api eff-handleCalls px h = MessageCallback-  (selectMessageWithLazy-    (\case-      (Cast _ :: Request api) -> Nothing-      callReq                 -> Just callReq-    )-  )-  (\(Call callRef fromPid req :: Request api) -> h-    req-    (\resAction -> do-      (mReply, cbResult) <- resAction-      traverse_ (sendReply (mkRequestOrigin req fromPid callRef)) mReply-      return cbResult-    )-  )----- | A smart constructor for 'MessageCallback's------ @since 0.13.2-handleCastsAndCalls-  :: forall api eff effScheduler-   . ( HasCallStack-     , Typeable api-     , Typeable (Api api 'Asynchronous)-     , SetMember Process (Process effScheduler) eff-     , Member Interrupts eff-     )-  => SchedulerProxy effScheduler-  -> (Api api 'Asynchronous -> Eff eff CallbackResult)-  -> (  forall secret reply-      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))-     => Api api ( 'Synchronous reply)-     -> (Eff eff (Maybe reply, CallbackResult) -> secret)-     -> secret-     )-  -> MessageCallback api eff-handleCastsAndCalls px onCast onCall =-  handleCalls px onCall <> handleCasts onCast----- | A variation of 'handleCalls' that allows to defer a reply to a call.------ @since 0.14.2-handleCallsDeferred-  :: forall api eff effScheduler-   . ( HasCallStack-     , Typeable api-     , SetMember Process (Process effScheduler) eff-     , Member Interrupts eff-     )-  => SchedulerProxy effScheduler-  -> (  forall reply-      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))-     => RequestOrigin (Api api ( 'Synchronous reply))-     -> Api api ( 'Synchronous reply)-     -> Eff eff CallbackResult-     )-  -> MessageCallback api eff-handleCallsDeferred px h = MessageCallback-  (selectMessageWithLazy-    (\case-      (Cast _ :: Request api) -> Nothing-      callReq                 -> Just callReq-    )-  )-  (\(Call callRef fromPid req :: Request api) ->-    h (RequestOrigin fromPid callRef) req-  )--type family ResponseType request where-  ResponseType (Api a ('Synchronous r)) = r----- | A smart constructor for 'MessageCallback's------ @since 0.13.2-handleProcessDowns-  :: forall eff-   . HasCallStack-  => (MonitorReference -> Eff eff CallbackResult)-  -> MessageCallback '[] eff-handleProcessDowns k = MessageCallback selectMessage (k . downReference)---- | Compose two 'Api's to a type-leve pair of them.------ > handleCalls api1calls ^: handleCalls api2calls ^:------ @since 0.13.2-(^:)-  :: forall (api1 :: Type) (apis2 :: [Type]) eff-   . HasCallStack-  => MessageCallback api1 eff-  -> MessageCallback apis2 eff-  -> MessageCallback (api1 ': apis2) eff-(MessageCallback selL runL) ^: (MessageCallback selR runR) =-  MessageCallback (Left <$> selL <|> Right <$> selR) (either runL runR)--infixr 5 ^:---- | Make a fallback handler, i.e. a handler to which no other can be composed--- to from the right.------ @since 0.13.2-fallbackHandler-  :: forall api eff-   . HasCallStack-  => MessageCallback api eff-  -> MessageCallback '[] eff-fallbackHandler (MessageCallback s r) = MessageCallback s r---- | A 'fallbackHandler' that drops the left-over messages.------ @since 0.13.2-dropUnhandledMessages :: forall eff . HasCallStack => MessageCallback '[] eff-dropUnhandledMessages =-  MessageCallback selectAnyMessageLazy (const (return AwaitNext))---- | A 'fallbackHandler' that terminates if there are unhandled messages.------ @since 0.13.2-exitOnUnhandled :: forall eff . HasCallStack => MessageCallback '[] eff-exitOnUnhandled = MessageCallback selectAnyMessageLazy $ \msg ->-  return (StopServer (ProcessError ("unhandled message " ++ show msg)))---- | A 'fallbackHandler' that drops the left-over messages.------ @since 0.13.2-logUnhandledMessages-  :: forall eff-   . (Member (Logs LogMessage) eff, HasCallStack)-  => MessageCallback '[] eff-logUnhandledMessages = MessageCallback selectAnyMessageLazy $ \msg -> do-  logWarning ("ignoring unhandled message " ++ show msg)-  return AwaitNext---- | Helper type class for the return values of 'spawnApiServer' et al.------ @since 0.13.2-class ToServerPids (t :: k) where-  type ServerPids t-  toServerPids :: proxy t -> ProcessId -> ServerPids t--instance ToServerPids '[] where-  type ServerPids '[] = ProcessId-  toServerPids _ = id--instance-  forall (api1 :: Type) (api2 :: [Type])-  . (ToServerPids api1, ToServerPids api2)-  => ToServerPids (api1 ': api2) where-  type ServerPids (api1 ': api2) = (ServerPids api1, ServerPids api2)-  toServerPids _ p =-    (toServerPids (Proxy @api1) p, toServerPids (Proxy @api2) p)--instance-  forall (api1 :: Type)-  . (ToServerPids api1)-  => ToServerPids api1 where-  type ServerPids api1 = Server api1-  toServerPids _ = asServer---- | Just a wrapper around a function that will be applied to the result of--- a 'MessageCallback's 'StopServer' clause, or an 'InterruptReason' caught during--- the execution of @receive@ or a 'MessageCallback'------ @since 0.13.2-data InterruptCallback eff where-   InterruptCallback ::-     (InterruptReason -> Eff eff CallbackResult) -> InterruptCallback eff--instance Default (InterruptCallback eff) where-  def = stopServerOnInterrupt---- | A smart constructor for 'InterruptCallback's------ @since 0.13.2-stopServerOnInterrupt :: forall eff . HasCallStack => InterruptCallback eff-stopServerOnInterrupt = InterruptCallback (pure . StopServer)---- | Apply a given callback function to incoming 'Observeration's.------ @since 0.14.1-handleObservations-  :: Typeable o-  => (Server o -> Observation o -> Eff e CallbackResult)-  -> MessageCallback (Observing o) e-handleObservations cb = handleCasts $ \(Observered s o) -> cb s o---- | An 'Api' type for generic 'Observer's, see 'handleObservations'.------ @since 0.14.1-data Observing o-  deriving Typeable---- | An 'Api' instance for generic 'Observer's, see 'handleObservations'.------ @since 0.14.1-data instance Api (Observing o) 'Asynchronous where-  Observered :: Server o -> Observation o -> Api (Observing o) 'Asynchronous--instance (Typeable o, Observable o) => Observer (Observing o) o where-  observationMessage = Observered
src/Control/Eff/Concurrent/Process.hs view
@@ -22,9 +22,6 @@   , ResumeProcess(..)   -- ** Scheduler Effect Identification   , SchedulerProxy(..)-  , HasScheduler-  , getSchedulerProxy-  , withSchedulerProxy   , thisSchedulerProxy   -- ** Process State   , ProcessState(..)@@ -404,27 +401,6 @@   -- | Like 'SP' but different   Scheduler :: SchedulerProxy q --- | A constraint for the implicit 'SchedulerProxy' parameter.--- Use 'getSchedulerProxy' to query it. _EXPERIMENTAL_------ @since 0.12.0-type HasScheduler q = (?_schedulerProxy :: SchedulerProxy q)---- | Get access to the 'SchedulerProxy' for the current scheduler effects.---  _EXPERIMENTAL_------ @since 0.12.0-getSchedulerProxy :: HasScheduler q => SchedulerProxy q-getSchedulerProxy = ?_schedulerProxy---- | Set the 'SchedulerProxy' to use, this satisfies 'HasScheduler' .---  _EXPERIMENTAL_------ @since 0.12.0-withSchedulerProxy :: SchedulerProxy q -> (HasScheduler q => a) -> a-withSchedulerProxy px x = let ?_schedulerProxy = px in x-- -- | /Cons/ 'Process' onto a list of effects. type ConsProcess r = Process r ': r @@ -667,10 +643,9 @@ -- via a call to 'interrupt'. exitOnInterrupt   :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r)-  => SchedulerProxy q-  -> Eff r a+  => Eff r a   -> Eff r a-exitOnInterrupt px = handleInterrupts (exitBecause px . NotRecovered)+exitOnInterrupt = handleInterrupts (exitBecause . NotRecovered)  -- | Handle 'InterruptReason's arising during process operations, e.g. -- when a linked process crashes while we wait in a 'receiveSelectedMessage'@@ -807,9 +782,8 @@ yieldProcess   :: forall r q    . (SetMember Process (Process q) r, HasCallStack, Member Interrupts r)-  => SchedulerProxy q-  -> Eff r ()-yieldProcess _ = executeAndResumeOrThrow YieldProcess+  => Eff r ()+yieldProcess = executeAndResumeOrThrow YieldProcess  -- | Send a message to a process addressed by the 'ProcessId'. -- See 'SendMessage'.@@ -821,11 +795,10 @@      , Member Interrupts r      , Typeable o      )-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> o   -> Eff r ()-sendMessage _ pid message =+sendMessage pid message =   executeAndResumeOrThrow (SendMessage pid $! toDyn $! message)  -- | Send a 'Dynamic' value to a process addressed by the 'ProcessId'.@@ -833,11 +806,10 @@ sendAnyMessage   :: forall r q    . (SetMember Process (Process q) r, HasCallStack, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> Dynamic   -> Eff r ()-sendAnyMessage _ pid message =+sendAnyMessage pid message =   rnf pid `seq` executeAndResumeOrThrow (SendMessage pid $! message)  -- | Exit a process addressed by the 'ProcessId'. The process will exit,@@ -846,11 +818,10 @@ sendShutdown   :: forall r q    . (SetMember Process (Process q) r, HasCallStack, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> ExitReason 'NoRecovery   -> Eff r ()-sendShutdown _ pid s =+sendShutdown pid s =   pid `deepseq` s `deepseq` executeAndResumeOrThrow (SendShutdown pid s)  -- | Interrupts a process addressed by the 'ProcessId'. The process might exit,@@ -859,11 +830,10 @@ sendInterrupt   :: forall r q    . (SetMember Process (Process q) r, HasCallStack, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> InterruptReason   -> Eff r ()-sendInterrupt _ pid s =+sendInterrupt pid s =   pid `deepseq` s `deepseq` executeAndResumeOrThrow (SendInterrupt pid s)  -- | Start a new process, the new process will execute an effect, the function@@ -923,10 +893,9 @@ isProcessAlive   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> Eff r Bool-isProcessAlive _px pid =+isProcessAlive  pid =   isJust <$> executeAndResumeOrThrow (GetProcessState pid)  -- | Block until a message was received.@@ -934,9 +903,8 @@ receiveAnyMessage   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> Eff r Dynamic-receiveAnyMessage _ =+  => Eff r Dynamic+receiveAnyMessage =   executeAndResumeOrThrow (ReceiveSelectedMessage selectAnyMessageLazy)  -- | Block until a message was received, that is not 'Nothing' after applying@@ -949,10 +917,9 @@      , SetMember Process (Process q) r      , Member Interrupts r      )-  => SchedulerProxy q-  -> MessageSelector a+  => MessageSelector a   -> Eff r a-receiveSelectedMessage _ f = executeAndResumeOrThrow (ReceiveSelectedMessage f)+receiveSelectedMessage f = executeAndResumeOrThrow (ReceiveSelectedMessage f)  -- | Receive and cast the message to some 'Typeable' instance. -- See 'ReceiveSelectedMessage' for more documentation.@@ -965,9 +932,8 @@      , SetMember Process (Process q) r      , Member Interrupts r      )-  => SchedulerProxy q-  -> Eff r a-receiveMessage px = receiveSelectedMessage px (MessageSelector fromDynamic)+  => Eff r a+receiveMessage = receiveSelectedMessage (MessageSelector fromDynamic)  -- | Remove and return all messages currently enqueued in the process message -- queue.@@ -978,7 +944,6 @@    . ( HasCallStack      , SetMember Process (Process q) r      , Member Interrupts r-     , HasScheduler q      )   => Eff r [Dynamic] flushMessages =@@ -995,50 +960,45 @@ receiveSelectedLoop   :: forall r q a endOfLoopResult    . (SetMember Process (Process q) r, HasCallStack)-  => SchedulerProxy q-  -> MessageSelector a+  => MessageSelector a   -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult))   -> Eff r endOfLoopResult-receiveSelectedLoop px selectMesage handlers = do+receiveSelectedLoop selectMesage handlers = do   mReq <- send (ReceiveSelectedMessage @q @a selectMesage)   mRes <- case mReq of     Interrupted reason  -> handlers (Left reason)     ResumeWith  message -> handlers (Right message)-  maybe (receiveSelectedLoop px selectMesage handlers) return mRes+  maybe (receiveSelectedLoop selectMesage handlers) return mRes  -- | Like 'receiveSelectedLoop' but /not selective/. -- See also 'selectAnyMessageLazy', 'receiveSelectedLoop'. receiveAnyLoop   :: forall r q endOfLoopResult    . (SetMember Process (Process q) r, HasCallStack)-  => SchedulerProxy q-  -> (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult))+  => (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult))   -> Eff r endOfLoopResult-receiveAnyLoop px = receiveSelectedLoop px selectAnyMessageLazy+receiveAnyLoop = receiveSelectedLoop selectAnyMessageLazy  -- | Like 'receiveSelectedLoop' but refined to casting to a specific 'Typeable' -- using 'selectMessageLazy'. receiveLoop   :: forall r q a endOfLoopResult    . (SetMember Process (Process q) r, HasCallStack, Typeable a)-  => SchedulerProxy q-  -> (Either InterruptReason a -> Eff r (Maybe endOfLoopResult))+  => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult))   -> Eff r endOfLoopResult-receiveLoop px = receiveSelectedLoop px selectMessageLazy+receiveLoop = receiveSelectedLoop selectMessageLazy  -- | Returns the 'ProcessId' of the current process. self   :: (HasCallStack, SetMember Process (Process q) r)-  => SchedulerProxy q-  -> Eff r ProcessId-self _px = executeAndResumeOrExit SelfPid+  => Eff r ProcessId+self = executeAndResumeOrExit SelfPid  -- | Generate a unique 'Int' for the current process. makeReference   :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> Eff r Int-makeReference _px = executeAndResumeOrThrow MakeReference+  => Eff r Int+makeReference = executeAndResumeOrThrow MakeReference  -- | A value that contains a unique reference of a process -- monitoring.@@ -1072,10 +1032,9 @@ monitor   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> Eff r MonitorReference-monitor _px = executeAndResumeOrThrow . Monitor . force+monitor = executeAndResumeOrThrow . Monitor . force  -- | Remove a monitor created with 'monitor'. --@@ -1083,10 +1042,9 @@ demonitor   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> MonitorReference+  => MonitorReference   -> Eff r ()-demonitor _px = executeAndResumeOrThrow . Demonitor . force+demonitor = executeAndResumeOrThrow . Demonitor . force  -- | 'monitor' another process before while performing an action -- and 'demonitor' afterwards.@@ -1098,11 +1056,10 @@      , SetMember Process (Process q) r      , Member Interrupts r      )-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> (MonitorReference -> Eff r a)   -> Eff r a-withMonitor px pid eff = monitor px pid >>= \ref -> eff ref <* demonitor px ref+withMonitor pid eff = monitor pid >>= \ref -> eff ref <* demonitor ref  -- | A 'MessageSelector' for receiving either a monitor of the -- given process or another message.@@ -1116,15 +1073,12 @@      , Typeable a      , Show a      )-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> MessageSelector a   -> Eff r (Either ProcessDown a)-receiveWithMonitor px pid sel = withMonitor-  px+receiveWithMonitor pid sel = withMonitor   pid   (\ref -> receiveSelectedMessage-    px     (Left <$> selectProcessDown ref <|> Right <$> sel)   ) @@ -1176,10 +1130,9 @@ linkProcess   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> Eff r ()-linkProcess _px = executeAndResumeOrThrow . Link . force+linkProcess = executeAndResumeOrThrow . Link . force  -- | Unlink the calling proccess from the other process. --@@ -1187,36 +1140,32 @@ unlinkProcess   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> Eff r ()-unlinkProcess _px = executeAndResumeOrThrow . Unlink . force+unlinkProcess = executeAndResumeOrThrow . Unlink . force  -- | Exit the process with a 'ProcessExitReaon'. exitBecause   :: forall r q a    . (HasCallStack, SetMember Process (Process q) r)-  => SchedulerProxy q-  -> ExitReason 'NoRecovery+  => ExitReason 'NoRecovery   -> Eff r a-exitBecause _ = send . Shutdown @q . force+exitBecause = send . Shutdown @q . force  -- | Exit the process. exitNormally   :: forall r q a    . (HasCallStack, SetMember Process (Process q) r)-  => SchedulerProxy q-  -> Eff r a-exitNormally px = exitBecause px ExitNormally+  => Eff r a+exitNormally = exitBecause  ExitNormally  -- | Exit the process with an error. exitWithError   :: forall r q a    . (HasCallStack, SetMember Process (Process q) r)-  => SchedulerProxy q-  -> String+  => String   -> Eff r a-exitWithError px = exitBecause px . NotRecovered . ProcessError+exitWithError = exitBecause . NotRecovered . ProcessError  -- | Each process is identified by a single process id, that stays constant -- throughout the life cycle of a process. Also, message sending relies on these
src/Control/Eff/Concurrent/Process/Interactive.hs view
@@ -86,7 +86,7 @@       Right nextAction -> do         res <- nextAction         traverse_ (lift . putStrLn . (">>> " ++)) res-        yieldProcess SP+        yieldProcess         readEvalPrintLoop queueVar    where     readAction = lift $ atomically $ do@@ -138,7 +138,7 @@   -> Server o   -> Api o 'Asynchronous   -> IO ()-submitCast sc svr request = submit sc (cast SchedulerProxy svr request)+submitCast sc svr request = submit sc (cast svr request)  -- | Combination of 'submit' and 'cast'. submitCall@@ -154,4 +154,4 @@   -> Server o   -> Api o ( 'Synchronous q)   -> IO q-submitCall sc svr request = submit sc (call SchedulerProxy svr request)+submitCall sc svr request = submit sc (call svr request)
src/Control/Eff/Concurrent/Process/SingleThreadedScheduler.hs view
@@ -63,10 +63,11 @@     . showString " msgQs: "     . appEndo         (foldMap-          (\(pid, msgs) -> Endo (showString "  " . shows pid . showString ": ")-            <> foldMap (\m -> Endo (shows (dynTypeRep m))) (toList msgs)+          (\(pid, msgs) ->+            Endo (showString "  " . shows pid . showString ": ")+              <> foldMap (\m -> Endo (shows (dynTypeRep m))) (toList msgs)           )-          (sts ^.. msgQs . itraversed . withIndex  )+          (sts ^.. msgQs . itraversed . withIndex)         )     ) @@ -301,26 +302,25 @@     -> OnYield r a  instance Show (OnYield r a) where-  show =-    \case-      OnFlushMessages _ -> "OnFlushMessages"-      OnYield _ -> "OnYield"-      OnSelf _ -> "OnSelf"-      OnSpawn False _ _ -> "OnSpawn"-      OnSpawn True _ _ -> "OnSpawn (link)"-      OnDone _ -> "OnDone"-      OnShutdown e -> "OnShutdown " ++ show e-      OnInterrupt e _ -> "OnInterrupt "++ show e-      OnSend toP _ _ -> "OnSend " ++ show toP-      OnRecv _ _ -> "OnRecv"-      OnGetProcessState p _ -> "OnGetProcessState " ++ show p-      OnSendShutdown p e _ -> "OnSendShutdow " ++ show p ++ " " ++ show e-      OnSendInterrupt p e _ -> "OnSendInterrupt " ++ show p ++ " " ++ show e-      OnMakeReference _ -> "OnMakeReference"-      OnMonitor p _ -> "OnMonitor " ++ show p-      OnDemonitor p _ -> "OnDemonitor " ++ show p-      OnLink p _ -> "OnLink " ++ show p-      OnUnlink p _ -> "OnUnlink " ++ show p+  show = \case+    OnFlushMessages _     -> "OnFlushMessages"+    OnYield         _     -> "OnYield"+    OnSelf          _     -> "OnSelf"+    OnSpawn False _ _     -> "OnSpawn"+    OnSpawn True  _ _     -> "OnSpawn (link)"+    OnDone     _          -> "OnDone"+    OnShutdown e          -> "OnShutdown " ++ show e+    OnInterrupt e _       -> "OnInterrupt " ++ show e+    OnSend toP _ _        -> "OnSend " ++ show toP+    OnRecv            _ _ -> "OnRecv"+    OnGetProcessState p _ -> "OnGetProcessState " ++ show p+    OnSendShutdown  p e _ -> "OnSendShutdow " ++ show p ++ " " ++ show e+    OnSendInterrupt p e _ -> "OnSendInterrupt " ++ show p ++ " " ++ show e+    OnMakeReference _     -> "OnMakeReference"+    OnMonitor   p _       -> "OnMonitor " ++ show p+    OnDemonitor p _       -> "OnDemonitor " ++ show p+    OnLink      p _       -> "OnLink " ++ show p+    OnUnlink    p _       -> "OnUnlink " ++ show p  runAsCoroutinePure   :: forall v r m@@ -357,9 +357,8 @@ handleProcess _sts Empty =   return $ Left (NotRecovered (ProcessError "no main process")) -handleProcess sts allProcs@((!processState, !pid) :<| rest)-  = let-      handleExit res = if pid == 0+handleProcess sts allProcs@((!processState, !pid) :<| rest) =+  let handleExit res = if pid == 0         then return res         else do           let (downPids, stsNew) = removeLinksTo pid sts@@ -382,128 +381,126 @@               )             )             nextTargets-    in-      case processState of-        OnDone     r    -> handleExit (Right r)+  in+    case processState of+      OnDone     r    -> handleExit (Right r) -        OnShutdown e    -> handleExit (Left e)+      OnShutdown e    -> handleExit (Left e) -        OnInterrupt e k -> do-          nextK <- diskontinue sts k e-          handleProcess sts (rest :|> (nextK, pid))+      OnInterrupt e k -> do+        nextK <- diskontinue sts k e+        handleProcess sts (rest :|> (nextK, pid)) -        OnSendInterrupt targetPid sr k -> doSendInterrupt targetPid sr k+      OnSendInterrupt targetPid sr k -> doSendInterrupt targetPid sr k -        OnSendShutdown  targetPid sr k -> do-          let allButTarget =-                Seq.filter (\(_, e) -> e /= pid && e /= targetPid) allProcs-              targets = Seq.filter (\(_, e) -> e == targetPid) allProcs-              suicide = targetPid == pid-          if suicide-            then handleExit (Left sr)-            else do-              let deliverTheGoodNews (targetState, tPid) = do-                    nextTargetState <- case targetState of-                      OnSendInterrupt _ _ _tk -> return (OnShutdown sr)-                      OnSendShutdown  _ _ _tk -> return (OnShutdown sr)-                      OnFlushMessages _tk     -> return (OnShutdown sr)-                      OnYield _tk             -> return (OnShutdown sr)-                      OnSelf  _tk             -> return (OnShutdown sr)-                      OnSend _ _ _tk          -> return (OnShutdown sr)-                      OnRecv _ _tk            -> return (OnShutdown sr)-                      OnSpawn _ _ _tk         -> return (OnShutdown sr)-                      OnDone x                -> return (OnDone x)-                      OnGetProcessState _ _tk -> return (OnShutdown sr)-                      OnShutdown sr'          -> return (OnShutdown sr')-                      OnInterrupt _er _tk     -> return (OnShutdown sr)-                      OnMakeReference _tk     -> return (OnShutdown sr)-                      OnMonitor   _ _tk       -> return (OnShutdown sr)-                      OnDemonitor _ _tk       -> return (OnShutdown sr)-                      OnLink      _ _tk       -> return (OnShutdown sr)-                      OnUnlink    _ _tk       -> return (OnShutdown sr)-                    return (nextTargetState, tPid)-              nextTargets <- _runEff sts $ traverse deliverTheGoodNews targets-              nextK       <- kontinue sts k ()-              handleProcess-                sts-                (allButTarget Seq.>< (nextTargets :|> (nextK, pid)))+      OnSendShutdown  targetPid sr k -> do+        let allButTarget =+              Seq.filter (\(_, e) -> e /= pid && e /= targetPid) allProcs+            targets = Seq.filter (\(_, e) -> e == targetPid) allProcs+            suicide = targetPid == pid+        if suicide+          then handleExit (Left sr)+          else do+            let deliverTheGoodNews (targetState, tPid) = do+                  nextTargetState <- case targetState of+                    OnSendInterrupt _ _ _tk -> return (OnShutdown sr)+                    OnSendShutdown  _ _ _tk -> return (OnShutdown sr)+                    OnFlushMessages _tk     -> return (OnShutdown sr)+                    OnYield         _tk     -> return (OnShutdown sr)+                    OnSelf          _tk     -> return (OnShutdown sr)+                    OnSend _ _ _tk          -> return (OnShutdown sr)+                    OnRecv _ _tk            -> return (OnShutdown sr)+                    OnSpawn _ _ _tk         -> return (OnShutdown sr)+                    OnDone x                -> return (OnDone x)+                    OnGetProcessState _ _tk -> return (OnShutdown sr)+                    OnShutdown sr'          -> return (OnShutdown sr')+                    OnInterrupt _er _tk     -> return (OnShutdown sr)+                    OnMakeReference _tk     -> return (OnShutdown sr)+                    OnMonitor   _ _tk       -> return (OnShutdown sr)+                    OnDemonitor _ _tk       -> return (OnShutdown sr)+                    OnLink      _ _tk       -> return (OnShutdown sr)+                    OnUnlink    _ _tk       -> return (OnShutdown sr)+                  return (nextTargetState, tPid)+            nextTargets <- _runEff sts $ traverse deliverTheGoodNews targets+            nextK       <- kontinue sts k ()+            handleProcess sts+                          (allButTarget Seq.>< (nextTargets :|> (nextK, pid))) -        OnSelf k -> do-          nextK <- kontinue sts k pid-          handleProcess sts (rest :|> (nextK, pid))+      OnSelf k -> do+        nextK <- kontinue sts k pid+        handleProcess sts (rest :|> (nextK, pid)) -        OnMakeReference k -> do-          let (ref, stsNext) = incRef sts-          nextK <- kontinue sts k ref-          handleProcess stsNext (rest :|> (nextK, pid))+      OnMakeReference k -> do+        let (ref, stsNext) = incRef sts+        nextK <- kontinue sts k ref+        handleProcess stsNext (rest :|> (nextK, pid)) -        OnYield k -> do-          sts ^. yieldEff-          nextK <- kontinue sts k ()-          handleProcess sts (rest :|> (nextK, pid))+      OnYield k -> do+        sts ^. yieldEff+        nextK <- kontinue sts k ()+        handleProcess sts (rest :|> (nextK, pid)) -        OnSend toPid msg k -> do-          nextK <- kontinue sts k ()-          handleProcess (enqueueMsg toPid msg sts) (rest :|> (nextK, pid))+      OnSend toPid msg k -> do+        nextK <- kontinue sts k ()+        handleProcess (enqueueMsg toPid msg sts) (rest :|> (nextK, pid)) -        OnGetProcessState toPid k -> do-          nextK <- kontinue sts k (getProcessState toPid sts)-          handleProcess sts (rest :|> (nextK, pid))+      OnGetProcessState toPid k -> do+        nextK <- kontinue sts k (getProcessState toPid sts)+        handleProcess sts (rest :|> (nextK, pid)) -        OnSpawn link f k -> do-          let (newPid, newSts) =-                newProcessQ (if link then Just pid else Nothing) sts-          fk    <- runAsCoroutinePure (newSts ^. runEff) (f >> exitNormally SP)-          nextK <- kontinue newSts k newPid-          handleProcess newSts (rest :|> (fk, newPid) :|> (nextK, pid))+      OnSpawn link f k -> do+        let (newPid, newSts) =+              newProcessQ (if link then Just pid else Nothing) sts+        fk    <- runAsCoroutinePure (newSts ^. runEff) (f >> exitNormally)+        nextK <- kontinue newSts k newPid+        handleProcess newSts (rest :|> (fk, newPid) :|> (nextK, pid)) -        OnFlushMessages k -> do-          let (msgs, newSts) = flushMsgs pid sts-          nextK <- kontinue newSts k msgs-          handleProcess newSts (rest :|> (nextK, pid))+      OnFlushMessages k -> do+        let (msgs, newSts) = flushMsgs pid sts+        nextK <- kontinue newSts k msgs+        handleProcess newSts (rest :|> (nextK, pid)) -        recv@(OnRecv messageSelector k) ->-          case receiveMsg pid messageSelector sts of-            Nothing -> do-              nextK <- diskontinue-                sts-                k-                (ProcessError (show pid ++ " has no message queue"))+      recv@(OnRecv messageSelector k) ->+        case receiveMsg pid messageSelector sts of+          Nothing -> do+            nextK <- diskontinue+              sts+              k+              (ProcessError (show pid ++ " has no message queue")) +            handleProcess sts (rest :|> (nextK, pid))+          Just Nothing -> if Seq.length rest == 0+            then do+              nextK <- diskontinue sts+                                   k+                                   (ProcessError (show pid ++ " deadlocked"))               handleProcess sts (rest :|> (nextK, pid))-            Just Nothing -> if Seq.length rest == 0-              then do-                nextK <- diskontinue-                  sts-                  k-                  (ProcessError (show pid ++ " deadlocked"))-                handleProcess sts (rest :|> (nextK, pid))-              else handleProcess sts (rest :|> (recv, pid))-            Just (Just (result, newSts)) -> do-              nextK <- kontinue newSts k result-              handleProcess newSts (rest :|> (nextK, pid))+            else handleProcess sts (rest :|> (recv, pid))+          Just (Just (result, newSts)) -> do+            nextK <- kontinue newSts k result+            handleProcess newSts (rest :|> (nextK, pid)) -        OnMonitor toPid k -> do-          let (ref, stsNew) = addMonitoring pid toPid sts-          nextK <- kontinue stsNew k ref-          handleProcess stsNew (rest :|> (nextK, pid))+      OnMonitor toPid k -> do+        let (ref, stsNew) = addMonitoring pid toPid sts+        nextK <- kontinue stsNew k ref+        handleProcess stsNew (rest :|> (nextK, pid)) -        OnDemonitor monRef k -> do-          let stsNew = removeMonitoring monRef sts-          nextK <- kontinue stsNew k ()-          handleProcess stsNew (rest :|> (nextK, pid))+      OnDemonitor monRef k -> do+        let stsNew = removeMonitoring monRef sts+        nextK <- kontinue stsNew k ()+        handleProcess stsNew (rest :|> (nextK, pid)) -        OnLink toPid k -> do-          let (downInterrupts, stsNew) = addLink pid toPid sts-          nextK <- case downInterrupts of-            Nothing -> kontinue stsNew k ()-            Just i  -> diskontinue stsNew k i-          handleProcess stsNew (rest :|> (nextK, pid))+      OnLink toPid k -> do+        let (downInterrupts, stsNew) = addLink pid toPid sts+        nextK <- case downInterrupts of+          Nothing -> kontinue stsNew k ()+          Just i  -> diskontinue stsNew k i+        handleProcess stsNew (rest :|> (nextK, pid)) -        OnUnlink toPid k -> do-          let (_, stsNew) = removeLinksTo toPid sts-          nextK <- kontinue stsNew k ()-          handleProcess stsNew (rest :|> (nextK, pid))+      OnUnlink toPid k -> do+        let (_, stsNew) = removeLinksTo toPid sts+        nextK <- kontinue stsNew k ()+        handleProcess stsNew (rest :|> (nextK, pid))  where   doSendInterrupt targetPid sr k = do     let suicide = targetPid == pid@@ -524,8 +521,8 @@             OnSendInterrupt _ _ tk -> tk (Interrupted sr)             OnSendShutdown  _ _ tk -> tk (Interrupted sr)             OnFlushMessages tk     -> tk (Interrupted sr)-            OnYield tk             -> tk (Interrupted sr)-            OnSelf  tk             -> tk (Interrupted sr)+            OnYield         tk     -> tk (Interrupted sr)+            OnSelf          tk     -> tk (Interrupted sr)             OnSend _ _ tk          -> tk (Interrupted sr)             OnRecv _ tk            -> tk (Interrupted sr)             OnSpawn _ _ tk         -> tk (Interrupted sr)@@ -544,11 +541,7 @@  -- | The concrete list of 'Eff'ects for running this pure scheduler on @IO@ and -- with string logging.-type LoggingAndIo =-              '[ Logs LogMessage-               , LogWriterReader LogMessage IO-               , Lift IO-               ]+type LoggingAndIo = '[Logs LogMessage, LogWriterReader LogMessage IO, Lift IO]  -- | A 'SchedulerProxy' for 'LoggingAndIo'. singleThreadedIoScheduler :: SchedulerProxy LoggingAndIo
src/Control/Eff/Concurrent/Process/Timer.hs view
@@ -44,11 +44,10 @@      , NFData a      , Show a      )-  => SchedulerProxy q-  -> Timeout+  => Timeout   -> Eff r (Maybe a)-receiveAfter px t =-  either (const Nothing) Just <$> receiveSelectedAfter px (selectMessage @a) t+receiveAfter t =+  either (const Nothing) Just <$> receiveSelectedAfter (selectMessage @a) t  -- | Wait for a message of the given type for the given time. When no message -- arrives in time, return 'Left' 'TimerElapsed'. This is based on@@ -63,16 +62,14 @@      , Member Interrupts r      , Show a      )-  => SchedulerProxy q-  -> MessageSelector a+  => MessageSelector a   -> Timeout   -> Eff r (Either TimerElapsed a)-receiveSelectedAfter px sel t = do-  timerRef <- startTimer px t+receiveSelectedAfter sel t = do+  timerRef <- startTimer t   res      <- receiveSelectedMessage-    px     (Left <$> selectTimerElapsed timerRef <|> Right <$> sel)-  cancelTimer px timerRef+  cancelTimer timerRef   return res  -- | A 'MessageSelector' matching 'TimerElapsed' messages created by@@ -92,7 +89,7 @@  instance Show Timeout where   showsPrec d (TimeoutMicros t) =-    showParen (d>=10) (showString "timeout: " . shows t . showString " µs")+    showParen (d >= 10) (showString "timeout: " . shows t . showString " µs")  -- | The reference to a timer started by 'startTimer', required to stop -- a timer via 'cancelTimer'.@@ -103,7 +100,7 @@  instance Show TimerReference where   showsPrec d (TimerReference t) =-    showParen (d>=10) (showString "timer: " . shows t)+    showParen (d >= 10) (showString "timer: " . shows t)  -- | A value to be sent when timer started with 'startTimer' has elapsed. --@@ -113,7 +110,7 @@  instance Show TimerElapsed where   showsPrec d (TimerElapsed t) =-    showParen (d>=10) (shows t . showString " elapsed")--+    showParen (d >= 10) (shows t . showString " elapsed")-- -- @since 0.12.0  @@ -131,20 +128,16 @@      , Typeable message      , NFData message      )-  => SchedulerProxy q-  -> ProcessId+  => ProcessId   -> Timeout   -> (TimerReference -> message)   -> Eff r TimerReference-sendAfter px pid (TimeoutMicros 0) mkMsg = TimerReference <$> spawn-  (   yieldProcess px-  >>  self px-  >>= (sendMessage SP pid . force . mkMsg . TimerReference)-  )-sendAfter px pid (TimeoutMicros t) mkMsg = TimerReference <$> spawn+sendAfter pid (TimeoutMicros 0) mkMsg = TimerReference <$> spawn+  (yieldProcess >> self >>= (sendMessage pid . force . mkMsg . TimerReference))+sendAfter pid (TimeoutMicros t) mkMsg = TimerReference <$> spawn   (   liftIO (threadDelay t)-  >>  self px-  >>= (sendMessage SP pid . force . mkMsg . TimerReference)+  >>  self+  >>= (sendMessage pid . force . mkMsg . TimerReference)   )  -- | Start a new timer, after the time has elapsed, 'TimerElapsed' is sent to@@ -161,12 +154,11 @@      , SetMember Process (Process q) r      , Member Interrupts r      )-  => SchedulerProxy q-  -> Timeout+  => Timeout   -> Eff r TimerReference-startTimer px t = do-  p <- self px-  sendAfter px p t TimerElapsed+startTimer t = do+  p <- self+  sendAfter p t TimerElapsed  -- | Cancel a timer started with 'startTimer'. --@@ -178,7 +170,6 @@      , SetMember Process (Process q) r      , Member Interrupts r      )-  => SchedulerProxy q-  -> TimerReference+  => TimerReference   -> Eff r ()-cancelTimer px (TimerReference tr) = sendShutdown px tr ExitNormally+cancelTimer (TimerReference tr) = sendShutdown tr ExitNormally
test/ForkIOScheduler.hs view
@@ -45,21 +45,14 @@                   doExit                 lift (threadDelay 100000) -                me <- self forkIoScheduler-                spawn_-                  (lift (threadDelay 10000) >> sendMessage forkIoScheduler me ()-                  )-                eres <- receiveWithMonitor forkIoScheduler-                                           p1-                                           (selectMessage @())+                me <- self+                spawn_ (lift (threadDelay 10000) >> sendMessage me ())+                eres <- receiveWithMonitor p1 (selectMessage @())                 case eres of                   Left  _down -> lift (atomically (putTMVar aVar False))-                  Right ()    -> withMonitor forkIoScheduler p1 $ \ref -> do-                    sendShutdown forkIoScheduler-                                 p1-                                 (NotRecovered (ProcessError "test 123"))-                    _down <- receiveSelectedMessage forkIoScheduler-                                                    (selectProcessDown ref)+                  Right ()    -> withMonitor p1 $ \ref -> do+                    sendShutdown p1 (NotRecovered (ProcessError "test 123"))+                    _down <- receiveSelectedMessage (selectProcessDown ref)                     lift (atomically (putTMVar aVar True))               )             )@@ -105,7 +98,7 @@       (1000 :: Natural)       def       (Scheduler.defaultMainWithLogChannel-        (void (spawn (void (receiveAnyMessage forkIoScheduler))))+        (void (spawn (void receiveAnyMessage)))       )     )   )@@ -119,8 +112,8 @@       def       (Scheduler.defaultMainWithLogChannel         (do-          void (spawn (void (receiveAnyMessage forkIoScheduler)))-          void (exitNormally forkIoScheduler)+          void (spawn (void receiveAnyMessage))+          void exitNormally           fail "This should not happen!!"         )       )@@ -138,11 +131,8 @@         def         (Scheduler.defaultMainWithLogChannel           (do-            void-              (spawn-                (foreverCheap (void (sendMessage forkIoScheduler 1000 "test")))-              )-            void (exitNormally forkIoScheduler)+            void (spawn (foreverCheap (void (sendMessage 1000 "test"))))+            void exitNormally             fail "This should not happen!!"           )         )@@ -159,8 +149,8 @@       def       (Scheduler.defaultMainWithLogChannel         (do-          child <- spawn (void (receiveMessage @String forkIoScheduler))-          sendMessage forkIoScheduler child "test"+          child <- spawn (void (receiveMessage @String))+          sendMessage child "test"           return ()         )       )@@ -177,14 +167,13 @@       (Scheduler.defaultMainWithLogChannel         (do           child <- spawn $ void $ provideInterrupts $ exitOnInterrupt-            forkIoScheduler             (do-              void (receiveMessage @String forkIoScheduler)-              void (exitNormally forkIoScheduler)+              void (receiveMessage @String)+              void exitNormally               error "This should not happen (child)!!"             )-          sendMessage forkIoScheduler child "test"-          void (exitNormally forkIoScheduler)+          sendMessage child "test"+          void exitNormally           error "This should not happen!!"         )       )@@ -200,24 +189,24 @@     $ do         let n = 100             testMsg :: Float-            testMsg = 123-            flushMsgs px = do-              res <- receiveSelectedAfter px (selectDynamicMessageLazy Just) 0+            testMsg   = 123+            flushMsgs = do+              res <- receiveSelectedAfter (selectDynamicMessageLazy Just) 0               case res of                 Left  _to -> return ()-                Right _   -> flushMsgs px-        me <- self SP+                Right _   -> flushMsgs+        me <- self         spawn_           (do-            replicateM_ n $ sendMessage SP me "bad message"-            replicateM_ n $ sendMessage SP me (3123 :: Integer)-            sendMessage SP me testMsg+            replicateM_ n $ sendMessage me "bad message"+            replicateM_ n $ sendMessage me (3123 :: Integer)+            sendMessage me testMsg           )         do-          res <- receiveAfter @Float SP 1000000+          res <- receiveAfter @Float 1000000           lift (res @?= Just testMsg)-        flushMsgs SP-        res <- receiveSelectedAfter SP (selectDynamicMessageLazy Just) 10000+        flushMsgs+        res <- receiveSelectedAfter (selectDynamicMessageLazy Just) 10000         case res of           Left  _ -> return ()           Right x -> lift (False @? "unexpected message in queue " ++ show x)
test/LoopTests.hs view
@@ -16,99 +16,94 @@                                                as Scheduler  test_loopTests :: TestTree-test_loopTests-    = let soMany = 1000000-      in-          setTravisTestOptions $ testGroup-              "Loops without space leaks"-              [ testCase-                      "scheduleMonadIOEff with many yields from replicateCheapM_"-                  $ do-                        res <--                            Scheduler.scheduleIOWithLogging-                                (multiMessageLogWriter-                                    ($! (putStrLn . (">>> " ++)))-                                )-                            $ replicateCheapM_ soMany-                            $ yieldProcess SP-                        res @=? Right ()-              , testCase-                      "replicateCheapM_ of strict Int increments via the state effect"-                  $ do-                        let-                            res = run-                                (execState-                                    (0 :: Int)-                                    ( replicateCheapM_ soMany-                                    $ modify (force . (+ 1))-                                    )-                                )-                        res @=? soMany-              , testCase-                      "'foreverCheap' inside a child process and 'replicateCheapM_' in the main process"-                  $ do-                        res <--                            Scheduler.scheduleIOWithLogging-                                    (multiMessageLogWriter-                                        ($! (putStrLn . (">>> " ++)))-                                    )+test_loopTests =+    let soMany = 1000000+    in+        setTravisTestOptions $ testGroup+            "Loops without space leaks"+            [ testCase+                    "scheduleMonadIOEff with many yields from replicateCheapM_"+                $ do+                      res <-+                          Scheduler.scheduleIOWithLogging+                                  (multiMessageLogWriter+                                      ($! (putStrLn . (">>> " ++)))+                                  )+                              $ replicateCheapM_ soMany yieldProcess+                      res @=? Right ()+            , testCase+                    "replicateCheapM_ of strict Int increments via the state effect"+                $ do+                      let+                          res = run+                              (execState+                                  (0 :: Int)+                                  ( replicateCheapM_ soMany+                                  $ modify (force . (+ 1))+                                  )+                              )+                      res @=? soMany+            , testCase+                    "'foreverCheap' inside a child process and 'replicateCheapM_' in the main process"+                $ do+                      res <-+                          Scheduler.scheduleIOWithLogging+                                  (multiMessageLogWriter+                                      ($! (putStrLn . (">>> " ++)))+                                  ) -                                $ do-                                      me <- self SP-                                      spawn_-                                          (foreverCheap $ sendMessage SP me ()-                                          )-                                      replicateCheapM_-                                          soMany-                                          (void (receiveMessage @() SP))+                              $ do+                                    me <- self+                                    spawn_ (foreverCheap $ sendMessage me ())+                                    replicateCheapM_+                                        soMany+                                        (void (receiveMessage @())) -                        res @=? Right ()-              ]+                      res @=? Right ()+            ]   test_loopWithLeaksTests :: TestTree-test_loopWithLeaksTests-    = let soMany = 1000000-      in-          setTravisTestOptions $ testGroup-              "Loops WITH space leaks"-              [ testCase "scheduleMonadIOEff with many yields from replicateM_"-                  $ do-                        res <--                            Scheduler.scheduleIOWithLogging-                                (multiMessageLogWriter-                                    ($! (putStrLn . (">>> " ++)))-                                )-                            $ replicateM_ soMany-                            $ yieldProcess SP-                        res @=? Right ()-              , testCase-                      "replicateM_ of strict Int increments via the state effect"-                  $ do-                        let-                            res =-                                run-                                    (execState-                                        (0 :: Int)-                                        ( replicateM_ soMany-                                        $ modify (force . (+ 1))-                                        )-                                    )-                        res @=? soMany-              , testCase-                      "'forever' inside a child process and 'replicateM_' in the main process"-                  $ do-                        res <--                            Scheduler.scheduleIOWithLogging-                                    (multiMessageLogWriter-                                        ($! (putStrLn . (">>> " ++)))-                                    )-                                $ do-                                      me <- self SP-                                      spawn_ (forever $ sendMessage SP me ())-                                      replicateM_-                                          soMany-                                          (void (receiveMessage @() SP))+test_loopWithLeaksTests =+    let soMany = 1000000+    in+        setTravisTestOptions $ testGroup+            "Loops WITH space leaks"+            [ testCase "scheduleMonadIOEff with many yields from replicateM_"+                $ do+                      res <-+                          Scheduler.scheduleIOWithLogging+                                  (multiMessageLogWriter+                                      ($! (putStrLn . (">>> " ++)))+                                  )+                              $ replicateM_ soMany yieldProcess+                      res @=? Right ()+            , testCase+                    "replicateM_ of strict Int increments via the state effect"+                $ do+                      let+                          res =+                              run+                                  (execState+                                      (0 :: Int)+                                      ( replicateM_ soMany+                                      $ modify (force . (+ 1))+                                      )+                                  )+                      res @=? soMany+            , testCase+                    "'forever' inside a child process and 'replicateM_' in the main process"+                $ do+                      res <-+                          Scheduler.scheduleIOWithLogging+                                  (multiMessageLogWriter+                                      ($! (putStrLn . (">>> " ++)))+                                  )+                              $ do+                                    me <- self+                                    spawn_ (forever $ sendMessage me ())+                                    replicateM_ soMany+                                                (void (receiveMessage @())) -                        res @=? Right ()-              ]+                      res @=? Right ()+            ]
test/ProcessBehaviourTestCases.hs view
@@ -4,1029 +4,971 @@ import           Data.Foldable                  ( traverse_ ) import qualified Data.Dynamic                  as Dynamic import           Data.Typeable-import           Data.Default-import           Control.Exception-import           Control.Concurrent-import           Control.Concurrent.STM-import           Control.Eff.Concurrent.Process-import           Control.Eff.Concurrent.Process.Timer-import           Control.Eff.Concurrent.Api-import           Control.Eff.Concurrent.Api.Client-import           Control.Eff.Concurrent.Api.Server-import qualified Control.Eff.Concurrent.Process.ForkIOScheduler-                                               as ForkIO-import qualified Control.Eff.Concurrent.Process.SingleThreadedScheduler-                                               as SingleThreaded-import           Control.Eff-import           Control.Eff.Extend-import           Control.Eff.Log-import           Control.Eff.Loop-import           Control.Eff.Lift-import           Control.Monad-import           Test.Tasty-import           Test.Tasty.HUnit-import           Common-import           Control.Applicative-import           Data.Void--testInterruptReason :: InterruptReason-testInterruptReason = ProcessError "test interrupt"--test_forkIo :: TestTree-test_forkIo = setTravisTestOptions $ withTestLogC-  (\c lc -> handleLoggingAndIO_ (ForkIO.schedule c) lc)-  (\factory -> testGroup "ForkIOScheduler" [allTests factory])---test_singleThreaded :: TestTree-test_singleThreaded = setTravisTestOptions $ withTestLogC-  (\e logC ->-        -- void (runLift (logToChannel logC (SingleThreaded.schedule (return ()) e)))-    let runEff-          :: Eff '[Logs LogMessage, LogWriterReader LogMessage IO, Lift IO] a-          -> IO a-        runEff = flip handleLoggingAndIO logC-    in  void $ SingleThreaded.scheduleM runEff yield e-  )-  (\factory -> testGroup "SingleThreadedScheduler" [allTests factory])--allTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-allTests schedulerFactory = localOption-  (timeoutSeconds 300)-  (testGroup-    "Process"-    [ errorTests schedulerFactory-    , sendShutdownTests schedulerFactory-    , concurrencyTests schedulerFactory-    , exitTests schedulerFactory-    , pingPongTests schedulerFactory-    , yieldLoopTests schedulerFactory-    , selectiveReceiveTests schedulerFactory-    , linkingTests schedulerFactory-    , monitoringTests schedulerFactory-    , timerTests schedulerFactory-    ]-  )--data ReturnToSender-  deriving Typeable--data instance Api ReturnToSender r where-  ReturnToSender :: ProcessId -> String -> Api ReturnToSender ('Synchronous Bool)-  StopReturnToSender :: Api ReturnToSender ('Synchronous ())--deriving instance Show (Api ReturnToSender x)--deriving instance Typeable (Api ReturnToSender x)--returnToSender-  :: forall q r-   . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> Server ReturnToSender-  -> String-  -> Eff r Bool-returnToSender px toP msg = do-  me      <- self px-  _       <- call px toP (ReturnToSender me msg)-  msgEcho <- receiveMessage @String px-  return (msgEcho == msg)--stopReturnToSender-  :: forall q r-   . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => SchedulerProxy q-  -> Server ReturnToSender-  -> Eff r ()-stopReturnToSender px toP = call px toP StopReturnToSender--returnToSenderServer-  :: forall q r-   . ( HasCallStack-     , SetMember Process (Process q) r-     , Member (Logs LogMessage) q-     , Member Interrupts r-     )-  => SchedulerProxy q-  -> Eff r (Server ReturnToSender)-returnToSenderServer px = asServer <$> spawn-  (serve px $ def-    { _callCallback = Just-                        (\m k -> case m of-                          StopReturnToSender -> do-                            k ()-                            return (StopApiServer testInterruptReason)-                          ReturnToSender fromP echoMsg -> do-                            sendMessage px fromP echoMsg-                            yieldProcess px-                            k True-                            return HandleNextRequest-                        )-    }-  )--selectiveReceiveTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-selectiveReceiveTests schedulerFactory = setTravisTestOptions-  (testGroup-    "selective receive tests"-    [ testCase "send 10 messages (from 1..10) and receive messages from 10 to 1"-    $ applySchedulerFactory schedulerFactory-    $ do-        let-          nMax = 10-          receiverLoop donePid = go nMax-           where-            go :: Int -> Eff (InterruptableProcess r) ()-            go 0 = sendMessage SP donePid True-            go n = do-              void $ receiveSelectedMessage SP (filterMessage (== n))-              go (n - 1)--          senderLoop receviverPid =-            traverse_ (sendMessage SP receviverPid) [1 .. nMax]--        me          <- self SP-        receiverPid <- spawn (receiverLoop me)-        spawn_ (senderLoop receiverPid)-        ok <- receiveMessage @Bool SP-        lift (ok @? "selective receive failed")-    , testCase "receive a message while waiting for a call reply"-    $ applySchedulerFactory schedulerFactory-    $ do-        srv <- returnToSenderServer SP-        ok  <- returnToSender SP srv "test"-        ()  <- stopReturnToSender SP srv-        lift (ok @? "selective receive failed")-    , testCase "flush messages"-    $ applySchedulerFactory schedulerFactory-    $ withSchedulerProxy SP-    $ do-        let px = SP-        me <- self px-        spawn_-          $  replicateM_ 10 (sendMessage px me True)-          >> sendMessage px me ()-        spawn_-          $  replicateM_ 10 (sendMessage px me (123.23411 :: Float))-          >> sendMessage px me ()-        spawn_-          $  replicateM_ 10 (sendMessage px me "123")-          >> sendMessage px me ()-        ()   <- receiveMessage px-        ()   <- receiveMessage px-        ()   <- receiveMessage px-        -- replicateCheapM_ 40 (yieldProcess px)-        msgs <- flushMessages-        lift (length msgs @?= 30)-    ]-  )---yieldLoopTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-yieldLoopTests schedulerFactory-  = let maxN = 100000-    in-      setTravisTestOptions-        (testGroup-          "yield tests"-          [ testCase-            "yield many times (replicateM_)"-            (applySchedulerFactory schedulerFactory-                                   (replicateM_ maxN (yieldProcess SP))-            )-          , testCase-            "yield many times (forM_)"-            (applySchedulerFactory-              schedulerFactory-              (forM_ [1 :: Int .. maxN] (\_ -> yieldProcess SP))-            )-          , testCase-            "construct an effect with an exit first, followed by many yields"-            (applySchedulerFactory-              schedulerFactory-              (do-                void (exitNormally SP)-                replicateM_ 1000000000000 (yieldProcess SP)-              )-            )-          ]-        )---data Ping = Ping ProcessId-  deriving (Eq, Show)--data Pong = Pong-  deriving (Eq, Show)--pingPongTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-pingPongTests schedulerFactory = testGroup-  "Yield Tests"-  [ testCase "ping pong a message between two processes, both don't yield"-  $ applySchedulerFactory schedulerFactory-  $ do-      let pongProc = foreverCheap $ do-            Ping pinger <- receiveMessage SP-            sendMessage SP pinger Pong-          pingProc ponger parent = do-            me <- self SP-            sendMessage SP ponger (Ping me)-            Pong <- receiveMessage SP-            sendMessage SP parent True-      pongPid <- spawn pongProc-      me      <- self SP-      spawn_ (pingProc pongPid me)-      ok <- receiveMessage @Bool SP-      lift (ok @? "ping pong failed")-  , testCase "ping pong a message between two processes, with massive yielding"-  $ applySchedulerFactory schedulerFactory-  $ do-      yieldProcess SP-      let pongProc = foreverCheap $ do-            yieldProcess SP-            Ping pinger <- receiveMessage SP-            yieldProcess SP-            sendMessage SP pinger Pong-            yieldProcess SP-          pingProc ponger parent = do-            yieldProcess SP-            me <- self SP-            yieldProcess SP-            sendMessage SP ponger (Ping me)-            yieldProcess SP-            Pong <- receiveMessage SP-            yieldProcess SP-            sendMessage SP parent True-            yieldProcess SP-      yieldProcess SP-      pongPid <- spawn pongProc-      yieldProcess SP-      me <- self SP-      yieldProcess SP-      spawn_ (pingProc pongPid me)-      yieldProcess SP-      ok <- receiveMessage @Bool SP-      yieldProcess SP-      lift (ok @? "ping pong failed")-      yieldProcess SP-  , testCase-    "the first message is not delayed, not even in cooperative scheduling (because of yield)"-  $ applySchedulerFactory schedulerFactory-  $ do-      pongVar <- lift newEmptyMVar-      let pongProc = foreverCheap $ do-            Pong <- receiveMessage SP-            lift (putMVar pongVar Pong)-      ponger <- spawn pongProc-      sendMessage SP ponger Pong-      let waitLoop = do-            p <- lift (tryTakeMVar pongVar)-            case p of-              Nothing -> do-                yieldProcess SP-                waitLoop-              Just r -> return r-      p <- waitLoop-      lift (p == Pong @? "ping pong failed")-  ]--errorTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-errorTests schedulerFactory-  = let-      px :: SchedulerProxy r-      px = SchedulerProxy-    in-      testGroup-        "causing and handling errors"-        [ testGroup-            "exitWithError"-            [ testCase "unhandled exitWithError"-            $ applySchedulerFactory schedulerFactory-            $ do-                void $ exitWithError px "test error"-                error "This should not happen"-            , testCase "cannot catch exitWithError"-            $ applySchedulerFactory schedulerFactory-            $ do-                void $ exitWithError px "test error 4"-                error "This should not happen"-            , testCase "multi process exitWithError"-            $ scheduleAndAssert schedulerFactory-            $ \assertEff -> do-                me <- self px-                let n = 15-                traverse_-                  (\(i :: Int) -> spawn $ foreverCheap-                    (void-                      (  sendMessage px (888888 + fromIntegral i) "test message"-                      >> yieldProcess px-                      )-                    )-                  )-                  [0 .. n]-                traverse_-                  (\(i :: Int) -> spawn $ do-                    void $ sendMessage px me i-                    void (exitWithError px (show i ++ " died"))-                    error "this should not be reached"-                  )-                  [0 .. n]-                oks <- replicateM (length [0 .. n]) (receiveMessage px)-                assertEff "" (sort oks == [0 .. n])-            ]-        ]--concurrencyTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-concurrencyTests schedulerFactory-  = let-      px :: SchedulerProxy r-      px = SchedulerProxy-      n  = 100-    in-      testGroup-        "concurrency tests"-        [ testCase-          "when main process exits the scheduler kills/cleans and returns"-        $ applySchedulerFactory schedulerFactory-        $ do-            me <- self px-            traverse_-              (const-                (spawn-                  (do-                    m <- receiveAnyMessage px-                    void (sendMessage px me m)-                  )-                )-              )-              [1 .. n]-            lift (threadDelay 1000)-        , testCase "new processes are executed before the parent process"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do -- start massive amount of children that exit as soon as they are-               -- executed, this will only work smoothly when scheduler schedules-               -- the new child before the parent-            traverse_ (const (spawn (exitNormally px))) [1 .. n]-            assertEff "" True-        , testCase "two concurrent processes"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me     <- self px-            child1 <- spawn-              (do-                m <- receiveAnyMessage px-                void (sendAnyMessage px me m)-              )-            child2 <- spawn (foreverCheap (void (sendMessage px 888888 "")))-            sendMessage px child1 "test"-            i <- receiveMessage px-            sendInterrupt px child2 testInterruptReason-            assertEff "" (i == "test")-        , testCase "most processes send foreverCheap"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me <- self px-            traverse_-              (\(i :: Int) -> spawn $ do-                when (i `rem` 5 == 0) $ void $ sendMessage px me i-                foreverCheap $ void (sendMessage px 888 "test message to 888")-              )-              [0 .. n]-            oks <- replicateM (length [0, 5 .. n]) (receiveMessage px)-            assertEff "" (sort oks == [0, 5 .. n])-        , testCase "most processes self foreverCheap"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me <- self px-            traverse_-              (\(i :: Int) -> spawn $ do-                when (i `rem` 5 == 0) $ void $ sendMessage px me i-                foreverCheap $ void (self px)-              )-              [0 .. n]-            oks <- replicateM (length [0, 5 .. n]) (receiveMessage px)-            assertEff "" (sort oks == [0, 5 .. n])-        , testCase "most processes sendShutdown foreverCheap"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me <- self px-            traverse_-              (\(i :: Int) -> spawn $ do-                when (i `rem` 5 == 0) $ void $ sendMessage px me i-                foreverCheap $ void (sendShutdown px 999 ExitNormally)-              )-              [0 .. n]-            oks <- replicateM (length [0, 5 .. n]) (receiveMessage px)-            assertEff "" (sort oks == [0, 5 .. n])-        , testCase "most processes spawn foreverCheap"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me <- self px-            traverse_-              (\(i :: Int) -> spawn $ do-                when (i `rem` 5 == 0) $ void $ sendMessage px me i-                parent <- self px-                foreverCheap-                  $ void-                      (spawn-                        (void (sendMessage px parent "test msg from child"))-                      )-              )-              [0 .. n]-            oks <- replicateM (length [0, 5 .. n]) (receiveMessage px)-            assertEff "" (sort oks == [0, 5 .. n])-        , testCase "most processes receive foreverCheap"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me <- self px-            traverse_-              (\(i :: Int) -> spawn $ do-                when (i `rem` 5 == 0) $ void $ sendMessage px me i-                foreverCheap $ void (receiveAnyMessage px)-              )-              [0 .. n]-            oks <- replicateM (length [0, 5 .. n]) (receiveMessage px)-            assertEff "" (sort oks == [0, 5 .. n])-        ]--exitTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-exitTests schedulerFactory =-  let-    px :: SchedulerProxy r-    px = SchedulerProxy-  in-    testGroup "process exit tests"-      $ [ testGroup-          "async exceptions"-          [ testCase-                (  "a process dies immediately if a "-                ++ show e-                ++ " is thrown, while "-                ++ busyWith-                )-              $ do-                  tidVar           <- newEmptyTMVarIO-                  schedulerDoneVar <- newEmptyTMVarIO-                  void $ forkIO $ do-                    void-                      $ try @SomeException-                      $ void-                      $ applySchedulerFactory schedulerFactory-                      $ do-                          tid <- lift $ myThreadId-                          lift $ atomically $ putTMVar tidVar tid-                          foreverCheap busyEffect-                    atomically $ putTMVar schedulerDoneVar ()-                  tid <- atomically $ takeTMVar tidVar-                  threadDelay 1000-                  throwTo tid e-                  void $ atomically $ takeTMVar schedulerDoneVar-          | e <- [ThreadKilled, UserInterrupt, HeapOverflow, StackOverflow]-          , (busyWith, busyEffect) <--            [ ( "receiving"-              , void-                (send-                  (ReceiveSelectedMessage @r (filterMessage (== "test message"))-                  )-                )-              )-            , ( "sending"-              , void-                (send (SendMessage @r 44444 (Dynamic.toDyn "test message")))-              )-            , ( "sending shutdown"-              , void (send (SendShutdown @r 44444 ExitNormally))-              )-            , ("selfpid-ing", void (send (SelfPid @r)))-            , ( "spawn-ing"-              , void-                (send-                  (Spawn @r-                    (void-                      (send (ReceiveSelectedMessage @r selectAnyMessageLazy))-                    )-                  )-                )-              )-            , ("sleeping", lift (threadDelay 100000))-            ]-          ]-        , testGroup-          "main thread exit not blocked by"-          [ testCase ("a child process, busy with " ++ busyWith)-            $ applySchedulerFactory schedulerFactory-            $ do-                void $ spawn $ foreverCheap busyEffect-                lift (threadDelay 10000)-          | (busyWith, busyEffect) <--            [ ( "receiving"-              , void-                (send-                  (ReceiveSelectedMessage @r (filterMessage (== "test message"))-                  )-                )-              )-            , ( "sending"-              , void-                (send (SendMessage @r 44444 (Dynamic.toDyn "test message")))-              )-            , ( "sending shutdown"-              , void (send (SendShutdown @r 44444 ExitNormally))-              )-            , ("selfpid-ing", void (send (SelfPid @r)))-            , ( "spawn-ing"-              , void-                (send-                  (Spawn @r-                    (void-                      (send (ReceiveSelectedMessage @r selectAnyMessageLazy))-                    )-                  )-                )-              )-            ]-          ]-        , testGroup-          "one process exits, the other continues unimpaired"-          [ testCase-              (  "process 2 exits with: "-              ++ howToExit-              ++ " - while process 1 is busy with: "-              ++ busyWith-              )-            $ scheduleAndAssert schedulerFactory-            $ \assertEff -> do-                p1 <- spawn $ foreverCheap busyEffect-                lift (threadDelay 1000)-                void $ spawn $ do-                  lift (threadDelay 1000)-                  doExit-                lift (threadDelay 100000)-                wasRunningP1 <- isProcessAlive SP p1-                sendShutdown px p1 ExitNormally-                lift (threadDelay 100000)-                stillRunningP1 <- isProcessAlive SP p1-                assertEff "the other process did not die still running"-                          (not stillRunningP1 && wasRunningP1)-          | (busyWith , busyEffect) <--            [ ( "receiving"-              , void-                (send-                  (ReceiveSelectedMessage @r (filterMessage (== "test message"))-                  )-                )-              )-            , ( "sending"-              , void-                (send (SendMessage @r 44444 (Dynamic.toDyn "test message")))-              )-            , ( "sending shutdown"-              , void (send (SendShutdown @r 44444 ExitNormally))-              )-            , ("selfpid-ing", void (send (SelfPid @r)))-            , ( "spawn-ing"-              , void-                (send-                  (Spawn @r-                    (void-                      (send (ReceiveSelectedMessage @r selectAnyMessageLazy))-                    )-                  )-                )-              )-            ]-          , (howToExit, doExit    ) <--            [ ("normally"        , void (exitNormally px))-            , ("simply returning", return ())-            , ( "raiseError"-              , void (interrupt (ProcessError "test error raised"))-              )-            , ("exitWithError", void (exitWithError px "test error exit"))-            , ( "sendShutdown to self"-              , do-                me <- self px-                void (sendShutdown px me ExitNormally)-              )-            ]-          ]-        ]---sendShutdownTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-sendShutdownTests schedulerFactory =-  let px :: SchedulerProxy r-      px = SchedulerProxy-  in  testGroup-        "sendShutdown"-        [ testCase "... self" $ applySchedulerFactory schedulerFactory $ do-          me <- self px-          void $ send (SendShutdown @r me ExitNormally)-          interrupt (ProcessError "sendShutdown must not return")-        , testCase "sendInterrupt to self"-        $ scheduleAndAssert schedulerFactory-        $ \assertEff -> do-            me <- self px-            r  <- send (SendInterrupt @r me (ProcessError "123"))-            assertEff-              "Interrupted must be returned"-              (case r of-                Interrupted (ProcessError "123") -> True-                _ -> False-              )-        , testGroup-          "... other process"-          [ testCase "while it is sending"-          $ scheduleAndAssert schedulerFactory-          $ \assertEff -> do-              me    <- self px-              other <- spawn-                (do-                  untilInterrupted-                    (SendMessage @r 666666 (Dynamic.toDyn "test"))-                  void (sendMessage px me "OK")-                )-              void (sendInterrupt px other testInterruptReason)-              a <- receiveMessage px-              assertEff "" (a == "OK")-          , testCase "while it is receiving"-          $ scheduleAndAssert schedulerFactory-          $ \assertEff -> do-              me    <- self px-              other <- spawn-                (do-                  untilInterrupted-                    (ReceiveSelectedMessage @r selectAnyMessageLazy)-                  void (sendMessage px me "OK")-                )-              void (sendInterrupt px other testInterruptReason)-              a <- receiveMessage px-              assertEff "" (a == "OK")-          , testCase "while it is self'ing"-          $ scheduleAndAssert schedulerFactory-          $ \assertEff -> do-              me    <- self px-              other <- spawn-                (do-                  untilInterrupted (SelfPid @r)-                  void (sendMessage px me "OK")-                )-              void (sendInterrupt px other (ProcessError "testError"))-              a <- receiveMessage px-              assertEff "" (a == "OK")-          , testCase "while it is spawning"-          $ scheduleAndAssert schedulerFactory-          $ \assertEff -> do-              me    <- self px-              other <- spawn-                (do-                  untilInterrupted (Spawn @r (return ()))-                  void (sendMessage px me "OK")-                )-              void (sendInterrupt px other testInterruptReason)-              a <- receiveMessage px-              assertEff "" (a == "OK")-          , testCase "while it is sending shutdown messages"-          $ scheduleAndAssert schedulerFactory-          $ \assertEff -> do-              me    <- self px-              other <- spawn-                (do-                  untilInterrupted (SendShutdown @r 777 ExitNormally)-                  void (sendMessage px me "OK")-                )-              void (sendInterrupt px other testInterruptReason)-              a <- receiveMessage px-              assertEff "" (a == "OK")-          , testCase "handleInterrupt handles my own interrupts"-          $ scheduleAndAssert schedulerFactory-          $ \assertEff ->-              handleInterrupts-                  (\e -> return (ProcessError "test" == e))-                  (interrupt (ProcessError "test") >> return False)-                >>= assertEff "exception handler not invoked"-          ]-        ]--linkingTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-linkingTests schedulerFactory = setTravisTestOptions-  (testGroup-    "process linking tests"-    [ testCase "link process with it self"-    $ applySchedulerFactory schedulerFactory-    $ do-        me <- self SP-        handleInterrupts-          (\er -> lift (False @? ("unexpected interrupt: " ++ show er)))-          (do-            linkProcess SP me-            lift (threadDelay 10000)-          )-    , testCase "link with not running process"-    $ applySchedulerFactory schedulerFactory-    $ do-        let testPid = 234234234-        handleInterrupts-          (lift . (@?= LinkedProcessCrashed testPid))-          (do-            linkProcess SP testPid-            void (receiveMessage @Void SP)-          )-    , testCase "linked process exit message is NormalExit"-    $ applySchedulerFactory schedulerFactory-    $ do-        foo <- spawn (void (receiveMessage @Void SP))-        handleInterrupts-          (lift . (\e -> e /= LinkedProcessCrashed foo @? show e))-          (do-            linkProcess SP foo-            sendShutdown SP foo ExitNormally-            lift (threadDelay 1000)-          )-    , testCase "linked process exit message is Crash"-    $ applySchedulerFactory schedulerFactory-    $ do-        foo <- spawn (void (receiveMessage @Void SP))-        handleInterrupts-          (lift . (@?= LinkedProcessCrashed foo))-          (do-            linkProcess SP foo-            sendShutdown SP foo Killed-            void (receiveMessage @Void SP)-          )-    , testCase "link multiple times"-    $ applySchedulerFactory schedulerFactory-    $ do-        foo <- spawn (void (receiveMessage @Void SP))-        handleInterrupts-          (lift . (@?= LinkedProcessCrashed foo))-          (do-            linkProcess SP foo-            linkProcess SP foo-            linkProcess SP foo-            linkProcess SP foo-            linkProcess SP foo-            linkProcess SP foo-            linkProcess SP foo-            sendShutdown SP foo Killed-            void (receiveMessage @Void SP)-          )-    , testCase "unlink multiple times"-    $ applySchedulerFactory schedulerFactory-    $ do-        foo <- spawn (void (receiveMessage @Void SP))-        handleInterrupts-          (lift . (False @?) . show)-          (do-            spawn_ (void (receiveAnyMessage SP))-            linkProcess SP foo-            linkProcess SP foo-            linkProcess SP foo-            unlinkProcess SP foo-            unlinkProcess SP foo-            unlinkProcess SP foo-            unlinkProcess SP foo-            withMonitor SP foo $ \ref -> do-              sendShutdown SP foo Killed-              void (receiveSelectedMessage SP (selectProcessDown ref))-          )-    , testCase "spawnLink" $ applySchedulerFactory schedulerFactory $ do-      let foo = void (receiveMessage @Void SP)-      handleInterrupts (\er -> lift (isBecauseDown Nothing er @? show er)) $ do-        x <- spawnLink foo-        sendShutdown SP x Killed-        void (receiveMessage @Void SP)-    , testCase "ignore normal exit"-    $ applySchedulerFactory schedulerFactory-    $ do-        mainProc <- self SP-        let linkingServer = void $ exitOnInterrupt SP $ do-              logNotice "linker"-              foreverCheap $ do-                x <- receiveMessage SP-                linkProcess SP x-                sendMessage SP mainProc True-        linker <- spawnLink linkingServer-        logNotice "mainProc"-        do-          x <- spawnLink (logNotice "x 1" >> void (receiveMessage @Void SP))-          withMonitor SP x $ \xRef -> do-            sendMessage SP linker x-            void $ receiveSelectedMessage SP (filterMessage id)-            sendShutdown SP x ExitNormally-            void (receiveSelectedMessage SP (selectProcessDown xRef))-        do-          x <- spawnLink (logNotice "x 2" >> void (receiveMessage @Void SP))-          withMonitor SP x $ \xRef -> do-            sendMessage SP linker x-            void $ receiveSelectedMessage SP (filterMessage id)-            sendShutdown SP x ExitNormally-            void (receiveSelectedMessage SP (selectProcessDown xRef))-        handleInterrupts (lift . (LinkedProcessCrashed linker @=?)) $ do-          sendShutdown SP linker Killed-          void (receiveMessage @Void SP)-    , testCase "unlink" $ applySchedulerFactory schedulerFactory $ do-      let-        foo1 = void (receiveAnyMessage SP)-        foo2 foo1Pid = do-          linkProcess SP foo1Pid-          (r1, barPid) <- receiveMessage SP-          lift ("unlink foo1" @=? r1)-          unlinkProcess SP foo1Pid-          sendMessage SP barPid ("unlinked foo1", foo1Pid)-          receiveMessage SP >>= lift . (@?= "the end")-          exitWithError SP "foo two"-        bar foo2Pid parentPid = do-          linkProcess SP foo2Pid-          me <- self SP-          sendMessage SP foo2Pid ("unlink foo1", me)-          (r1, foo1Pid) <- receiveMessage SP-          lift ("unlinked foo1" @=? r1)-          handleInterrupts-            (const (return ()))-            (do-              linkProcess SP foo1Pid-              sendShutdown SP foo1Pid Killed-              void (receiveMessage @Void SP)-            )-          handleInterrupts-            (\er ->-              void-                (sendMessage SP parentPid (LinkedProcessCrashed foo2Pid == er))-            )-            (do-              sendMessage SP foo2Pid "the end"-              void (receiveAnyMessage SP)-            )-      foo1Pid <- spawn foo1-      foo2Pid <- spawn (foo2 foo1Pid)-      me      <- self SP-      barPid  <- spawn (bar foo2Pid me)-      handleInterrupts-        (\er -> lift (LinkedProcessCrashed barPid @?= er))-        (do-          res <- receiveMessage @Bool SP-          lift (threadDelay 100000)-          lift (res @?= True)-        )-    ]-  )--monitoringTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-monitoringTests schedulerFactory = setTravisTestOptions-  (testGroup-    "process monitoring tests"-    [ testCase "monitored process not running"-    $ applySchedulerFactory schedulerFactory-    $ do-        let badPid = 132123-        ref <- monitor SP badPid-        pd  <- receiveSelectedMessage SP (selectProcessDown ref)-        lift (downReason pd @?= SomeExitReason (ProcessNotRunning badPid))-        lift (threadDelay 10000)-    , testCase "monitored process exit normally"-    $ applySchedulerFactory schedulerFactory-    $ do-        target <- spawn (receiveMessage SP >>= exitBecause SP)-        ref    <- monitor SP target-        sendMessage SP target ExitNormally-        pd <- receiveSelectedMessage SP (selectProcessDown ref)-        lift (downReason pd @?= SomeExitReason ExitNormally)-        lift (threadDelay 10000)-    , testCase "multiple monitors some demonitored"-    $ applySchedulerFactory schedulerFactory-    $ do-        target <- spawn (receiveMessage SP >>= exitBecause SP)-        ref1   <- monitor SP target-        ref2   <- monitor SP target-        ref3   <- monitor SP target-        ref4   <- monitor SP target-        ref5   <- monitor SP target-        demonitor SP ref3-        demonitor SP ref5-        sendMessage SP target ExitNormally-        pd1 <- receiveSelectedMessage SP (selectProcessDown ref1)-        lift (downReason pd1 @?= SomeExitReason ExitNormally)-        pd2 <- receiveSelectedMessage SP (selectProcessDown ref2)-        lift (downReason pd2 @?= SomeExitReason ExitNormally)-        pd4 <- receiveSelectedMessage SP (selectProcessDown ref4)-        lift (downReason pd4 @?= SomeExitReason ExitNormally)-        lift (threadDelay 10000)-    , testCase "monitored process killed"-    $ applySchedulerFactory schedulerFactory-    $ do-        target <- spawn (receiveMessage SP >>= exitBecause SP)-        ref    <- monitor SP target-        sendMessage SP target Killed-        pd <- receiveSelectedMessage SP (selectProcessDown ref)-        lift (downReason pd @?= SomeExitReason Killed)-        lift (threadDelay 10000)-    , testCase "demonitored process killed"-    $ applySchedulerFactory schedulerFactory-    $ do-        target <- spawn (receiveMessage SP >>= exitBecause SP)-        ref    <- monitor SP target-        demonitor SP ref-        sendMessage SP target Killed-        me <- self SP-        spawn_ (lift (threadDelay 10000) >> sendMessage SP me ())-        pd <- receiveSelectedMessage-          SP-          (Right <$> selectProcessDown ref <|> Left <$> selectMessage @())-        lift (pd @?= Left ())-        lift (threadDelay 10000)-    ]-  )--timerTests-  :: forall r-   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)-  => IO (Eff (InterruptableProcess r) () -> IO ())-  -> TestTree-timerTests schedulerFactory = setTravisTestOptions-  (testGroup-    "process timer tests"-    [ testCase "receiveAfter into timeout"-    $ applySchedulerFactory schedulerFactory-    $ do-        pd <- receiveAfter @Void SP 1000-        lift (pd @?= Nothing)-        lift (threadDelay 10000)-    , testCase "receiveAfter no timeout"-    $ applySchedulerFactory schedulerFactory-    $ do-        me    <- self SP-        other <- spawn-          (do-            r <- receiveMessage @() SP-            lift (r @?= ())-            sendMessage SP me (123 :: Int)-          )-        pd1 <- receiveAfter @() SP 10000-        lift (pd1 @?= Nothing)-        sendMessage SP other ()-        pd2 <- receiveAfter @Int SP 10000-        lift (pd2 @?= Just 123)-        lift (threadDelay 10000)-    , testCase "many receiveAfters"-    $ applySchedulerFactory schedulerFactory-    $ do-        let n = 5-            testMsg :: Float-            testMsg = 123-        me    <- self SP-        other <- spawn-          (do-            replicateM_ n $ sendMessage SP me "bad message"-            r <- receiveMessage @() SP-            lift (r @?= ())-            replicateM_ n $ sendMessage SP me testMsg-          )-        receiveAfter @Float SP 100 >>= lift . (@?= Nothing)-        sendMessage SP other ()-        replicateM_-          n-          (do-            res <- receiveAfter @Float SP 10000+import           Control.Exception+import           Control.Concurrent+import           Control.Concurrent.STM+import           Control.Eff.Concurrent.Process+import           Control.Eff.Concurrent.Process.Timer+import           Control.Eff.Concurrent.Api+import           Control.Eff.Concurrent.Api.Client+import           Control.Eff.Concurrent.Api.Server+import qualified Control.Eff.Concurrent.Process.ForkIOScheduler+                                               as ForkIO+import qualified Control.Eff.Concurrent.Process.SingleThreadedScheduler+                                               as SingleThreaded+import           Control.Eff+import           Control.Eff.Extend+import           Control.Eff.Log+import           Control.Eff.Loop+import           Control.Eff.Lift+import           Control.Monad+import           Test.Tasty+import           Test.Tasty.HUnit+import           Common+import           Control.Applicative+import           Data.Void++testInterruptReason :: InterruptReason+testInterruptReason = ProcessError "test interrupt"++test_forkIo :: TestTree+test_forkIo = setTravisTestOptions $ withTestLogC+  (\c lc -> handleLoggingAndIO_ (ForkIO.schedule c) lc)+  (\factory -> testGroup "ForkIOScheduler" [allTests factory])+++test_singleThreaded :: TestTree+test_singleThreaded = setTravisTestOptions $ withTestLogC+  (\e logC ->+        -- void (runLift (logToChannel logC (SingleThreaded.schedule (return ()) e)))+    let runEff+          :: Eff '[Logs LogMessage, LogWriterReader LogMessage IO, Lift IO] a+          -> IO a+        runEff = flip handleLoggingAndIO logC+    in  void $ SingleThreaded.scheduleM runEff yield e+  )+  (\factory -> testGroup "SingleThreadedScheduler" [allTests factory])++allTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+allTests schedulerFactory = localOption+  (timeoutSeconds 300)+  (testGroup+    "Process"+    [ errorTests schedulerFactory+    , sendShutdownTests schedulerFactory+    , concurrencyTests schedulerFactory+    , exitTests schedulerFactory+    , pingPongTests schedulerFactory+    , yieldLoopTests schedulerFactory+    , selectiveReceiveTests schedulerFactory+    , linkingTests schedulerFactory+    , monitoringTests schedulerFactory+    , timerTests schedulerFactory+    ]+  )++data ReturnToSender+  deriving Typeable++data instance Api ReturnToSender r where+  ReturnToSender :: ProcessId -> String -> Api ReturnToSender ('Synchronous Bool)+  StopReturnToSender :: Api ReturnToSender ('Synchronous ())++deriving instance Show (Api ReturnToSender x)++deriving instance Typeable (Api ReturnToSender x)++returnToSender+  :: forall q r+   . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)+  => Server ReturnToSender+  -> String+  -> Eff r Bool+returnToSender toP msg = do+  me      <- self+  _       <- call toP (ReturnToSender me msg)+  msgEcho <- receiveMessage @String+  return (msgEcho == msg)++stopReturnToSender+  :: forall q r+   . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)+  => Server ReturnToSender+  -> Eff r ()+stopReturnToSender toP = call toP StopReturnToSender++returnToSenderServer+  :: forall q . ( HasCallStack, Member (Logs LogMessage) q )+  => Eff (InterruptableProcess q) (Server ReturnToSender)+returnToSenderServer = spawnApiServer+  (handleCalls (\m k -> k $+                        case m of+                          StopReturnToSender -> do+                            return (Nothing, StopServer testInterruptReason)+                          ReturnToSender fromP echoMsg -> do+                            sendMessage fromP echoMsg+                            yieldProcess+                            return (Just True, AwaitNext)+                        )+  ) stopServerOnInterrupt++selectiveReceiveTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+selectiveReceiveTests schedulerFactory = setTravisTestOptions+  (testGroup+    "selective receive tests"+    [ testCase "send 10 messages (from 1..10) and receive messages from 10 to 1"+    $ applySchedulerFactory schedulerFactory+    $ do+        let+          nMax = 10+          receiverLoop donePid = go nMax+           where+            go :: Int -> Eff (InterruptableProcess r) ()+            go 0 = sendMessage donePid True+            go n = do+              void $ receiveSelectedMessage (filterMessage (== n))+              go (n - 1)++          senderLoop receviverPid =+            traverse_ (sendMessage receviverPid) [1 .. nMax]++        me          <- self+        receiverPid <- spawn (receiverLoop me)+        spawn_ (senderLoop receiverPid)+        ok <- receiveMessage @Bool+        lift (ok @? "selective receive failed")+    , testCase "receive a message while waiting for a call reply"+    $ applySchedulerFactory schedulerFactory+    $ do+        srv <- returnToSenderServer+        ok  <- returnToSender srv "test"+        ()  <- stopReturnToSender srv+        lift (ok @? "selective receive failed")+    , testCase "flush messages" $ applySchedulerFactory schedulerFactory $ do+      me <- self+      spawn_ $ replicateM_ 10 (sendMessage me True) >> sendMessage me ()+      spawn_+        $  replicateM_ 10 (sendMessage me (123.23411 :: Float))+        >> sendMessage me ()+      spawn_ $ replicateM_ 10 (sendMessage me "123") >> sendMessage me ()+      ()   <- receiveMessage+      ()   <- receiveMessage+      ()   <- receiveMessage+      -- replicateCheapM_ 40 yieldProcess+      msgs <- flushMessages+      lift (length msgs @?= 30)+    ]+  )+++yieldLoopTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+yieldLoopTests schedulerFactory =+  let maxN = 100000+  in  setTravisTestOptions+        (testGroup+          "yield tests"+          [ testCase+            "yield many times (replicateM_)"+            (applySchedulerFactory schedulerFactory+                                   (replicateM_ maxN yieldProcess)+            )+          , testCase+            "yield many times (forM_)"+            (applySchedulerFactory+              schedulerFactory+              (forM_ [1 :: Int .. maxN] (\_ -> yieldProcess))+            )+          , testCase+            "construct an effect with an exit first, followed by many yields"+            (applySchedulerFactory+              schedulerFactory+              (do+                void exitNormally+                replicateM_ 1000000000000 yieldProcess+              )+            )+          ]+        )+++data Ping = Ping ProcessId+  deriving (Eq, Show)++data Pong = Pong+  deriving (Eq, Show)++pingPongTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+pingPongTests schedulerFactory = testGroup+  "Yield Tests"+  [ testCase "ping pong a message between two processes, both don't yield"+  $ applySchedulerFactory schedulerFactory+  $ do+      let pongProc = foreverCheap $ do+            Ping pinger <- receiveMessage+            sendMessage pinger Pong+          pingProc ponger parent = do+            me <- self+            sendMessage ponger (Ping me)+            Pong <- receiveMessage+            sendMessage parent True+      pongPid <- spawn pongProc+      me      <- self+      spawn_ (pingProc pongPid me)+      ok <- receiveMessage @Bool+      lift (ok @? "ping pong failed")+  , testCase "ping pong a message between two processes, with massive yielding"+  $ applySchedulerFactory schedulerFactory+  $ do+      yieldProcess+      let pongProc = foreverCheap $ do+            yieldProcess+            Ping pinger <- receiveMessage+            yieldProcess+            sendMessage pinger Pong+            yieldProcess+          pingProc ponger parent = do+            yieldProcess+            me <- self+            yieldProcess+            sendMessage ponger (Ping me)+            yieldProcess+            Pong <- receiveMessage+            yieldProcess+            sendMessage parent True+            yieldProcess+      yieldProcess+      pongPid <- spawn pongProc+      yieldProcess+      me <- self+      yieldProcess+      spawn_ (pingProc pongPid me)+      yieldProcess+      ok <- receiveMessage @Bool+      yieldProcess+      lift (ok @? "ping pong failed")+      yieldProcess+  , testCase+    "the first message is not delayed, not even in cooperative scheduling (because of yield)"+  $ applySchedulerFactory schedulerFactory+  $ do+      pongVar <- lift newEmptyMVar+      let pongProc = foreverCheap $ do+            Pong <- receiveMessage+            lift (putMVar pongVar Pong)+      ponger <- spawn pongProc+      sendMessage ponger Pong+      let waitLoop = do+            p <- lift (tryTakeMVar pongVar)+            case p of+              Nothing -> do+                yieldProcess+                waitLoop+              Just r -> return r+      p <- waitLoop+      lift (p == Pong @? "ping pong failed")+  ]++errorTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+errorTests schedulerFactory = testGroup+  "causing and handling errors"+  [ testGroup+      "exitWithError"+      [ testCase "unhandled exitWithError"+      $ applySchedulerFactory schedulerFactory+      $ do+          void $ exitWithError "test error"+          error "This should not happen"+      , testCase "cannot catch exitWithError"+      $ applySchedulerFactory schedulerFactory+      $ do+          void $ exitWithError "test error 4"+          error "This should not happen"+      , testCase "multi process exitWithError"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me <- self+          let n = 15+          traverse_+            (\(i :: Int) -> spawn $ foreverCheap+              (void+                (  sendMessage (888888 + fromIntegral i) "test message"+                >> yieldProcess+                )+              )+            )+            [0 .. n]+          traverse_+            (\(i :: Int) -> spawn $ do+              void $ sendMessage me i+              void (exitWithError (show i ++ " died"))+              error "this should not be reached"+            )+            [0 .. n]+          oks <- replicateM (length [0 .. n]) receiveMessage+          assertEff "" (sort oks == [0 .. n])+      ]+  ]++concurrencyTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+concurrencyTests schedulerFactory =+  let n = 100+  in+    testGroup+      "concurrency tests"+      [ testCase+        "when main process exits the scheduler kills/cleans and returns"+      $ applySchedulerFactory schedulerFactory+      $ do+          me <- self+          traverse_+            (const+              (spawn+                (do+                  m <- receiveAnyMessage+                  void (sendMessage me m)+                )+              )+            )+            [1 .. n]+          lift (threadDelay 1000)+      , testCase "new processes are executed before the parent process"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do -- start massive amount of children that exit as soon as they are+             -- executed, this will only work smoothly when scheduler schedules+             -- the new child before the parent+          traverse_ (const (spawn exitNormally)) [1 .. n]+          assertEff "" True+      , testCase "two concurrent processes"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me     <- self+          child1 <- spawn+            (do+              m <- receiveAnyMessage+              void (sendAnyMessage me m)+            )+          child2 <- spawn (foreverCheap (void (sendMessage 888888 "")))+          sendMessage child1 "test"+          i <- receiveMessage+          sendInterrupt child2 testInterruptReason+          assertEff "" (i == "test")+      , testCase "most processes send foreverCheap"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me <- self+          traverse_+            (\(i :: Int) -> spawn $ do+              when (i `rem` 5 == 0) $ void $ sendMessage me i+              foreverCheap $ void (sendMessage 888 "test message to 888")+            )+            [0 .. n]+          oks <- replicateM (length [0, 5 .. n]) receiveMessage+          assertEff "" (sort oks == [0, 5 .. n])+      , testCase "most processes self foreverCheap"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me <- self+          traverse_+            (\(i :: Int) -> spawn $ do+              when (i `rem` 5 == 0) $ void $ sendMessage me i+              foreverCheap $ void self+            )+            [0 .. n]+          oks <- replicateM (length [0, 5 .. n]) receiveMessage+          assertEff "" (sort oks == [0, 5 .. n])+      , testCase "most processes sendShutdown foreverCheap"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me <- self+          traverse_+            (\(i :: Int) -> spawn $ do+              when (i `rem` 5 == 0) $ void $ sendMessage me i+              foreverCheap $ void (sendShutdown 999 ExitNormally)+            )+            [0 .. n]+          oks <- replicateM (length [0, 5 .. n]) receiveMessage+          assertEff "" (sort oks == [0, 5 .. n])+      , testCase "most processes spawn foreverCheap"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me <- self+          traverse_+            (\(i :: Int) -> spawn $ do+              when (i `rem` 5 == 0) $ void $ sendMessage me i+              parent <- self+              foreverCheap $ void+                (spawn (void (sendMessage parent "test msg from child")))+            )+            [0 .. n]+          oks <- replicateM (length [0, 5 .. n]) receiveMessage+          assertEff "" (sort oks == [0, 5 .. n])+      , testCase "most processes receive foreverCheap"+      $ scheduleAndAssert schedulerFactory+      $ \assertEff -> do+          me <- self+          traverse_+            (\(i :: Int) -> spawn $ do+              when (i `rem` 5 == 0) $ void $ sendMessage me i+              foreverCheap $ void receiveAnyMessage+            )+            [0 .. n]+          oks <- replicateM (length [0, 5 .. n]) receiveMessage+          assertEff "" (sort oks == [0, 5 .. n])+      ]++exitTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+exitTests schedulerFactory =+  testGroup "process exit tests"+    $ [ testGroup+        "async exceptions"+        [ testCase+              (  "a process dies immediately if a "+              ++ show e+              ++ " is thrown, while "+              ++ busyWith+              )+            $ do+                tidVar           <- newEmptyTMVarIO+                schedulerDoneVar <- newEmptyTMVarIO+                void $ forkIO $ do+                  void+                    $ try @SomeException+                    $ void+                    $ applySchedulerFactory schedulerFactory+                    $ do+                        tid <- lift $ myThreadId+                        lift $ atomically $ putTMVar tidVar tid+                        foreverCheap busyEffect+                  atomically $ putTMVar schedulerDoneVar ()+                tid <- atomically $ takeTMVar tidVar+                threadDelay 1000+                throwTo tid e+                void $ atomically $ takeTMVar schedulerDoneVar+        | e <- [ThreadKilled, UserInterrupt, HeapOverflow, StackOverflow]+        , (busyWith, busyEffect) <-+          [ ( "receiving"+            , void+              (send+                (ReceiveSelectedMessage @r (filterMessage (== "test message")))+              )+            )+          , ( "sending"+            , void (send (SendMessage @r 44444 (Dynamic.toDyn "test message")))+            )+          , ( "sending shutdown"+            , void (send (SendShutdown @r 44444 ExitNormally))+            )+          , ("selfpid-ing", void (send (SelfPid @r)))+          , ( "spawn-ing"+            , void+              (send+                (Spawn @r+                  (void (send (ReceiveSelectedMessage @r selectAnyMessageLazy)))+                )+              )+            )+          , ("sleeping", lift (threadDelay 100000))+          ]+        ]+      , testGroup+        "main thread exit not blocked by"+        [ testCase ("a child process, busy with " ++ busyWith)+          $ applySchedulerFactory schedulerFactory+          $ do+              void $ spawn $ foreverCheap busyEffect+              lift (threadDelay 10000)+        | (busyWith, busyEffect) <-+          [ ( "receiving"+            , void+              (send+                (ReceiveSelectedMessage @r (filterMessage (== "test message")))+              )+            )+          , ( "sending"+            , void (send (SendMessage @r 44444 (Dynamic.toDyn "test message")))+            )+          , ( "sending shutdown"+            , void (send (SendShutdown @r 44444 ExitNormally))+            )+          , ("selfpid-ing", void (send (SelfPid @r)))+          , ( "spawn-ing"+            , void+              (send+                (Spawn @r+                  (void (send (ReceiveSelectedMessage @r selectAnyMessageLazy)))+                )+              )+            )+          ]+        ]+      , testGroup+        "one process exits, the other continues unimpaired"+        [ testCase+            (  "process 2 exits with: "+            ++ howToExit+            ++ " - while process 1 is busy with: "+            ++ busyWith+            )+          $ scheduleAndAssert schedulerFactory+          $ \assertEff -> do+              p1 <- spawn $ foreverCheap busyEffect+              lift (threadDelay 1000)+              void $ spawn $ do+                lift (threadDelay 1000)+                doExit+              lift (threadDelay 100000)+              wasRunningP1 <- isProcessAlive p1+              sendShutdown p1 ExitNormally+              lift (threadDelay 100000)+              stillRunningP1 <- isProcessAlive p1+              assertEff "the other process did not die still running"+                        (not stillRunningP1 && wasRunningP1)+        | (busyWith , busyEffect) <-+          [ ( "receiving"+            , void+              (send+                (ReceiveSelectedMessage @r (filterMessage (== "test message")))+              )+            )+          , ( "sending"+            , void (send (SendMessage @r 44444 (Dynamic.toDyn "test message")))+            )+          , ( "sending shutdown"+            , void (send (SendShutdown @r 44444 ExitNormally))+            )+          , ("selfpid-ing", void (send (SelfPid @r)))+          , ( "spawn-ing"+            , void+              (send+                (Spawn @r+                  (void (send (ReceiveSelectedMessage @r selectAnyMessageLazy)))+                )+              )+            )+          ]+        , (howToExit, doExit    ) <-+          [ ("normally"        , void exitNormally)+          , ("simply returning", return ())+          , ("raiseError", void (interrupt (ProcessError "test error raised")))+          , ("exitWithError"   , void (exitWithError "test error exit"))+          , ( "sendShutdown to self"+            , do+              me <- self+              void (sendShutdown me ExitNormally)+            )+          ]+        ]+      ]+++sendShutdownTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+sendShutdownTests schedulerFactory = testGroup+  "sendShutdown"+  [ testCase "... self" $ applySchedulerFactory schedulerFactory $ do+    me <- self+    void $ send (SendShutdown @r me ExitNormally)+    interrupt (ProcessError "sendShutdown must not return")+  , testCase "sendInterrupt to self"+  $ scheduleAndAssert schedulerFactory+  $ \assertEff -> do+      me <- self+      r  <- send (SendInterrupt @r me (ProcessError "123"))+      assertEff+        "Interrupted must be returned"+        (case r of+          Interrupted (ProcessError "123") -> True+          _ -> False+        )+  , testGroup+    "... other process"+    [ testCase "while it is sending"+    $ scheduleAndAssert schedulerFactory+    $ \assertEff -> do+        me    <- self+        other <- spawn+          (do+            untilInterrupted (SendMessage @r 666666 (Dynamic.toDyn "test"))+            void (sendMessage me "OK")+          )+        void (sendInterrupt other testInterruptReason)+        a <- receiveMessage+        assertEff "" (a == "OK")+    , testCase "while it is receiving"+    $ scheduleAndAssert schedulerFactory+    $ \assertEff -> do+        me    <- self+        other <- spawn+          (do+            untilInterrupted (ReceiveSelectedMessage @r selectAnyMessageLazy)+            void (sendMessage me "OK")+          )+        void (sendInterrupt other testInterruptReason)+        a <- receiveMessage+        assertEff "" (a == "OK")+    , testCase "while it is self'ing"+    $ scheduleAndAssert schedulerFactory+    $ \assertEff -> do+        me    <- self+        other <- spawn+          (do+            untilInterrupted (SelfPid @r)+            void (sendMessage me "OK")+          )+        void (sendInterrupt other (ProcessError "testError"))+        a <- receiveMessage+        assertEff "" (a == "OK")+    , testCase "while it is spawning"+    $ scheduleAndAssert schedulerFactory+    $ \assertEff -> do+        me    <- self+        other <- spawn+          (do+            untilInterrupted (Spawn @r (return ()))+            void (sendMessage me "OK")+          )+        void (sendInterrupt other testInterruptReason)+        a <- receiveMessage+        assertEff "" (a == "OK")+    , testCase "while it is sending shutdown messages"+    $ scheduleAndAssert schedulerFactory+    $ \assertEff -> do+        me    <- self+        other <- spawn+          (do+            untilInterrupted (SendShutdown @r 777 ExitNormally)+            void (sendMessage me "OK")+          )+        void (sendInterrupt other testInterruptReason)+        a <- receiveMessage+        assertEff "" (a == "OK")+    , testCase "handleInterrupt handles my own interrupts"+    $ scheduleAndAssert schedulerFactory+    $ \assertEff ->+        handleInterrupts (\e -> return (ProcessError "test" == e))+                         (interrupt (ProcessError "test") >> return False)+          >>= assertEff "exception handler not invoked"+    ]+  ]++linkingTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+linkingTests schedulerFactory = setTravisTestOptions+  (testGroup+    "process linking tests"+    [ testCase "link process with it self"+    $ applySchedulerFactory schedulerFactory+    $ do+        me <- self+        handleInterrupts+          (\er -> lift (False @? ("unexpected interrupt: " ++ show er)))+          (do+            linkProcess me+            lift (threadDelay 10000)+          )+    , testCase "link with not running process"+    $ applySchedulerFactory schedulerFactory+    $ do+        let testPid = 234234234+        handleInterrupts+          (lift . (@?= LinkedProcessCrashed testPid))+          (do+            linkProcess testPid+            void (receiveMessage @Void)+          )+    , testCase "linked process exit message is NormalExit"+    $ applySchedulerFactory schedulerFactory+    $ do+        foo <- spawn (void (receiveMessage @Void))+        handleInterrupts+          (lift . (\e -> e /= LinkedProcessCrashed foo @? show e))+          (do+            linkProcess foo+            sendShutdown foo ExitNormally+            lift (threadDelay 1000)+          )+    , testCase "linked process exit message is Crash"+    $ applySchedulerFactory schedulerFactory+    $ do+        foo <- spawn (void (receiveMessage @Void))+        handleInterrupts+          (lift . (@?= LinkedProcessCrashed foo))+          (do+            linkProcess foo+            sendShutdown foo Killed+            void (receiveMessage @Void)+          )+    , testCase "link multiple times"+    $ applySchedulerFactory schedulerFactory+    $ do+        foo <- spawn (void (receiveMessage @Void))+        handleInterrupts+          (lift . (@?= LinkedProcessCrashed foo))+          (do+            linkProcess foo+            linkProcess foo+            linkProcess foo+            linkProcess foo+            linkProcess foo+            linkProcess foo+            linkProcess foo+            sendShutdown foo Killed+            void (receiveMessage @Void)+          )+    , testCase "unlink multiple times"+    $ applySchedulerFactory schedulerFactory+    $ do+        foo <- spawn (void (receiveMessage @Void))+        handleInterrupts+          (lift . (False @?) . show)+          (do+            spawn_ (void receiveAnyMessage)+            linkProcess foo+            linkProcess foo+            linkProcess foo+            unlinkProcess foo+            unlinkProcess foo+            unlinkProcess foo+            unlinkProcess foo+            withMonitor foo $ \ref -> do+              sendShutdown foo Killed+              void (receiveSelectedMessage (selectProcessDown ref))+          )+    , testCase "spawnLink" $ applySchedulerFactory schedulerFactory $ do+      let foo = void (receiveMessage @Void)+      handleInterrupts (\er -> lift (isBecauseDown Nothing er @? show er)) $ do+        x <- spawnLink foo+        sendShutdown x Killed+        void (receiveMessage @Void)+    , testCase "ignore normal exit"+    $ applySchedulerFactory schedulerFactory+    $ do+        mainProc <- self+        let linkingServer = void $ exitOnInterrupt $ do+              logNotice "linker"+              foreverCheap $ do+                x <- receiveMessage+                linkProcess x+                sendMessage mainProc True+        linker <- spawnLink linkingServer+        logNotice "mainProc"+        do+          x <- spawnLink (logNotice "x 1" >> void (receiveMessage @Void))+          withMonitor x $ \xRef -> do+            sendMessage linker x+            void $ receiveSelectedMessage (filterMessage id)+            sendShutdown x ExitNormally+            void (receiveSelectedMessage (selectProcessDown xRef))+        do+          x <- spawnLink (logNotice "x 2" >> void (receiveMessage @Void))+          withMonitor x $ \xRef -> do+            sendMessage linker x+            void $ receiveSelectedMessage (filterMessage id)+            sendShutdown x ExitNormally+            void (receiveSelectedMessage (selectProcessDown xRef))+        handleInterrupts (lift . (LinkedProcessCrashed linker @=?)) $ do+          sendShutdown linker Killed+          void (receiveMessage @Void)+    , testCase "unlink" $ applySchedulerFactory schedulerFactory $ do+      let+        foo1 = void receiveAnyMessage+        foo2 foo1Pid = do+          linkProcess foo1Pid+          (r1, barPid) <- receiveMessage+          lift ("unlink foo1" @=? r1)+          unlinkProcess foo1Pid+          sendMessage barPid ("unlinked foo1", foo1Pid)+          receiveMessage >>= lift . (@?= "the end")+          exitWithError "foo two"+        bar foo2Pid parentPid = do+          linkProcess foo2Pid+          me <- self+          sendMessage foo2Pid ("unlink foo1", me)+          (r1, foo1Pid) <- receiveMessage+          lift ("unlinked foo1" @=? r1)+          handleInterrupts+            (const (return ()))+            (do+              linkProcess foo1Pid+              sendShutdown foo1Pid Killed+              void (receiveMessage @Void)+            )+          handleInterrupts+            (\er -> void+              (sendMessage parentPid (LinkedProcessCrashed foo2Pid == er))+            )+            (do+              sendMessage foo2Pid "the end"+              void receiveAnyMessage+            )+      foo1Pid <- spawn foo1+      foo2Pid <- spawn (foo2 foo1Pid)+      me      <- self+      barPid  <- spawn (bar foo2Pid me)+      handleInterrupts+        (\er -> lift (LinkedProcessCrashed barPid @?= er))+        (do+          res <- receiveMessage @Bool+          lift (threadDelay 100000)+          lift (res @?= True)+        )+    ]+  )++monitoringTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+monitoringTests schedulerFactory = setTravisTestOptions+  (testGroup+    "process monitoring tests"+    [ testCase "monitored process not running"+    $ applySchedulerFactory schedulerFactory+    $ do+        let badPid = 132123+        ref <- monitor badPid+        pd  <- receiveSelectedMessage (selectProcessDown ref)+        lift (downReason pd @?= SomeExitReason (ProcessNotRunning badPid))+        lift (threadDelay 10000)+    , testCase "monitored process exit normally"+    $ applySchedulerFactory schedulerFactory+    $ do+        target <- spawn (receiveMessage >>= exitBecause)+        ref    <- monitor target+        sendMessage target ExitNormally+        pd <- receiveSelectedMessage (selectProcessDown ref)+        lift (downReason pd @?= SomeExitReason ExitNormally)+        lift (threadDelay 10000)+    , testCase "multiple monitors some demonitored"+    $ applySchedulerFactory schedulerFactory+    $ do+        target <- spawn (receiveMessage >>= exitBecause)+        ref1   <- monitor target+        ref2   <- monitor target+        ref3   <- monitor target+        ref4   <- monitor target+        ref5   <- monitor target+        demonitor ref3+        demonitor ref5+        sendMessage target ExitNormally+        pd1 <- receiveSelectedMessage (selectProcessDown ref1)+        lift (downReason pd1 @?= SomeExitReason ExitNormally)+        pd2 <- receiveSelectedMessage (selectProcessDown ref2)+        lift (downReason pd2 @?= SomeExitReason ExitNormally)+        pd4 <- receiveSelectedMessage (selectProcessDown ref4)+        lift (downReason pd4 @?= SomeExitReason ExitNormally)+        lift (threadDelay 10000)+    , testCase "monitored process killed"+    $ applySchedulerFactory schedulerFactory+    $ do+        target <- spawn (receiveMessage >>= exitBecause)+        ref    <- monitor target+        sendMessage target Killed+        pd <- receiveSelectedMessage (selectProcessDown ref)+        lift (downReason pd @?= SomeExitReason Killed)+        lift (threadDelay 10000)+    , testCase "demonitored process killed"+    $ applySchedulerFactory schedulerFactory+    $ do+        target <- spawn (receiveMessage >>= exitBecause)+        ref    <- monitor target+        demonitor ref+        sendMessage target Killed+        me <- self+        spawn_ (lift (threadDelay 10000) >> sendMessage me ())+        pd <- receiveSelectedMessage++          (Right <$> selectProcessDown ref <|> Left <$> selectMessage @())+        lift (pd @?= Left ())+        lift (threadDelay 10000)+    ]+  )++timerTests+  :: forall r+   . (Member (Logs LogMessage) r, SetMember Lift (Lift IO) r)+  => IO (Eff (InterruptableProcess r) () -> IO ())+  -> TestTree+timerTests schedulerFactory = setTravisTestOptions+  (testGroup+    "process timer tests"+    [ testCase "receiveAfter into timeout"+    $ applySchedulerFactory schedulerFactory+    $ do+        pd <- receiveAfter @Void 1000+        lift (pd @?= Nothing)+        lift (threadDelay 10000)+    , testCase "receiveAfter no timeout"+    $ applySchedulerFactory schedulerFactory+    $ do+        me    <- self+        other <- spawn+          (do+            r <- receiveMessage @()+            lift (r @?= ())+            sendMessage me (123 :: Int)+          )+        pd1 <- receiveAfter @() 10000+        lift (pd1 @?= Nothing)+        sendMessage other ()+        pd2 <- receiveAfter @Int 10000+        lift (pd2 @?= Just 123)+        lift (threadDelay 10000)+    , testCase "many receiveAfters"+    $ applySchedulerFactory schedulerFactory+    $ do+        let n = 5+            testMsg :: Float+            testMsg = 123+        me    <- self+        other <- spawn+          (do+            replicateM_ n $ sendMessage me "bad message"+            r <- receiveMessage @()+            lift (r @?= ())+            replicateM_ n $ sendMessage me testMsg+          )+        receiveAfter @Float 100 >>= lift . (@?= Nothing)+        sendMessage other ()+        replicateM_+          n+          (do+            res <- receiveAfter @Float 10000             lift (res @?= Just testMsg)           ) 
test/SingleThreadedScheduler.hs view
@@ -18,19 +18,19 @@       @=? Scheduler.schedulePure               (do                   adderChild <- spawn $ do-                      (from, arg1, arg2) <- receiveMessage SP-                      sendMessage SP from ((arg1 + arg2) :: Int)-                      foreverCheap $ void $ receiveAnyMessage SP+                      (from, arg1, arg2) <- receiveMessage+                      sendMessage from ((arg1 + arg2) :: Int)+                      foreverCheap $ void $ receiveAnyMessage                    multChild <- spawn $ do-                      (from, arg1, arg2) <- receiveMessage SP-                      sendMessage SP from ((arg1 * arg2) :: Int)+                      (from, arg1, arg2) <- receiveMessage+                      sendMessage from ((arg1 * arg2) :: Int) -                  me <- self SP-                  sendMessage SP adderChild (me, 3 :: Int, 4 :: Int)-                  x <- receiveMessage @Int SP-                  sendMessage SP multChild (me, x, 6 :: Int)-                  receiveMessage @Int SP+                  me <- self+                  sendMessage adderChild (me, 3 :: Int, 4 :: Int)+                  x <- receiveMessage @Int+                  sendMessage multChild (me, x, 6 :: Int)+                  receiveMessage @Int               )     ] @@ -41,9 +41,8 @@         "spawn a child and exit normally"         (Scheduler.defaultMainSingleThreaded             (do-                void-                    (spawn (void (receiveAnyMessage singleThreadedIoScheduler)))-                void (exitNormally singleThreadedIoScheduler)+                void (spawn (void receiveAnyMessage))+                void exitNormally                 fail "This should not happen!!"             )         )@@ -58,12 +57,12 @@             (do                 child <- spawn                     (do-                        void (receiveMessage @String singleThreadedIoScheduler)-                        void (exitNormally singleThreadedIoScheduler)+                        void (receiveMessage @String)+                        void exitNormally                         error "This should not happen (child)!!"                     )-                sendMessage singleThreadedIoScheduler child (toDyn "test")-                void (exitNormally singleThreadedIoScheduler)+                sendMessage child (toDyn "test")+                void exitNormally                 error "This should not happen!!"             )         )