{-# LANGUAGE UndecidableInstances #-} -- | Proxies and containers for casts and calls. -- -- @since 0.15.0 module Control.Eff.Concurrent.Api.Request ( Request(..) , Reply(..) , mkRequestOrigin , RequestOrigin(..) , sendReply ) where import Data.Typeable ( Typeable ) import Data.Proxy import Control.Eff import Control.Eff.Concurrent.Api import Control.Eff.Concurrent.Process import GHC.TypeLits import Control.DeepSeq import GHC.Generics -- | A wrapper sum type for calls and casts for the methods of an 'Api' subtype -- -- @since 0.15.0 data Request api where Call :: forall api reply . (Typeable api, Typeable reply, Typeable (Api api ('Synchronous reply))) => Int -> ProcessId -> Api api ('Synchronous reply) -> Request api Cast :: forall api . (Typeable api, Typeable (Api api 'Asynchronous)) => Api api 'Asynchronous -> Request api deriving Typeable -- | The wrapper around replies to 'Call's. -- -- @since 0.15.0 data Reply request where Reply :: (Typeable api, Typeable reply) => Proxy (Api api ('Synchronous reply)) -> Int -> reply -> Reply (Api api ('Synchronous reply)) deriving Typeable -- | Get the @reply@ of an @Api foo ('Synchronous reply)@. -- -- @since 0.15.0 type family ReplyType request where ReplyType (Api api ('Synchronous reply)) = reply ReplyType (Api api 'Asynchronous) = TypeError ('Text "Asynchronous requests (aka casts) have no reply type." ) -- | Get the @reply@ of an @Api foo ('Synchronous reply)@. -- -- @since 0.15.0 type family ApiType request where ApiType (Api api 'Asynchronous) = api ApiType (Api api ('Synchronous reply)) = api -- | TODO remove mkRequestOrigin :: request -> ProcessId -> Int -> RequestOrigin request mkRequestOrigin _ = RequestOrigin -- | Wraps the source 'ProcessId' and a unique identifier for a 'Call'. -- -- @since 0.15.0 data RequestOrigin request = RequestOrigin { _requestOriginPid :: !ProcessId, _requestOriginCallRef :: !Int} deriving (Eq, Ord, Typeable, Show, Generic) instance NFData (RequestOrigin request) where -- | Send a 'Reply' to a 'Call'. -- -- @since 0.15.0 sendReply :: forall request reply api eff q . ( SetMember Process (Process q) eff , Member Interrupts eff , Typeable api , ApiType request ~ api , ReplyType request ~ reply , request ~ Api api ( 'Synchronous reply) , Typeable reply ) => RequestOrigin request -> reply -> Eff eff () sendReply origin reply = sendMessage (_requestOriginPid origin) (Reply (Proxy @request) (_requestOriginCallRef origin) $! reply)