-- | Wrap "Network.GRPC.Client.StreamType.IO" to handle binary serialization
--
-- **NOTE**: The custom binary gRPC format provided by @grapesy@ is designed
-- so that the type of each message during communication can be different.
-- The wrappers in this module lose this generalization: every input and every
-- output must be of the same type. If this is too severe a limitaiton, you
-- should use the functionality from "Network.GRPC.Client.Binary" instead.
module Network.GRPC.Client.StreamType.IO.Binary (
    -- * Run client handlers
    nonStreaming
  , clientStreaming
  , clientStreaming_
  , serverStreaming
  , biDiStreaming
  ) where

import Control.Monad.Reader
import Data.Binary
import Data.ByteString.Lazy qualified as Lazy (ByteString)

import Network.GRPC.Client (Connection)
import Network.GRPC.Client.StreamType.IO qualified as IO
import Network.GRPC.Common
import Network.GRPC.Common.Binary (decodeOrThrow)
import Network.GRPC.Common.StreamType
import Network.GRPC.Spec

{-------------------------------------------------------------------------------
  Run client handlers
-------------------------------------------------------------------------------}

-- | Wrapper for 'IO.nonStreaming' that handles binary serialization
nonStreaming :: forall inp out rpc m.
     ( Binary inp, Input  rpc ~ Lazy.ByteString
     , Binary out, Output rpc ~ Lazy.ByteString
     , MonadIO m
     )
  => Connection
  -> ClientHandler' NonStreaming (ReaderT Connection m) rpc
  -> inp -> m out
nonStreaming :: forall {k} inp out (rpc :: k) (m :: * -> *).
(Binary inp, Input rpc ~ ByteString, Binary out,
 Output rpc ~ ByteString, MonadIO m) =>
Connection
-> ClientHandler' 'NonStreaming (ReaderT Connection m) rpc
-> inp
-> m out
nonStreaming Connection
conn ClientHandler' 'NonStreaming (ReaderT Connection m) rpc
h inp
inp =
    Connection
-> ClientHandler' 'NonStreaming (ReaderT Connection m) rpc
-> Input rpc
-> m (Output rpc)
forall {k} (rpc :: k) (m :: * -> *).
Connection
-> ClientHandler' 'NonStreaming (ReaderT Connection m) rpc
-> Input rpc
-> m (Output rpc)
IO.nonStreaming Connection
conn ClientHandler' 'NonStreaming (ReaderT Connection m) rpc
h (inp -> ByteString
forall a. Binary a => a -> ByteString
encode inp
inp) m ByteString -> (ByteString -> m out) -> m out
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString -> m out
forall (m :: * -> *) a. (MonadIO m, Binary a) => ByteString -> m a
decodeOrThrow

-- | Wrapper for 'IO.clientStreaming' that handles binary serialization
clientStreaming :: forall inp out rpc m r.
     ( Binary inp, Input  rpc ~ Lazy.ByteString
     , Binary out, Output rpc ~ Lazy.ByteString
     , MonadIO m
     )
  => Connection
  -> ClientHandler' ClientStreaming (ReaderT Connection m) rpc
  -> (    (NextElem inp -> m ())
       -> m r
     )
  -> m (out, r)
clientStreaming :: forall {k} inp out (rpc :: k) (m :: * -> *) r.
(Binary inp, Input rpc ~ ByteString, Binary out,
 Output rpc ~ ByteString, MonadIO m) =>
Connection
-> ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
-> ((NextElem inp -> m ()) -> m r)
-> m (out, r)
clientStreaming Connection
conn ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
h (NextElem inp -> m ()) -> m r
k = do
    (out, r) <- Connection
-> ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
-> ((NextElem (Input rpc) -> m ()) -> m r)
-> m (Output rpc, r)
forall {k} (rpc :: k) (m :: * -> *) r.
MonadIO m =>
Connection
-> ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
-> ((NextElem (Input rpc) -> m ()) -> m r)
-> m (Output rpc, r)
IO.clientStreaming Connection
conn ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
h (((NextElem (Input rpc) -> m ()) -> m r) -> m (Output rpc, r))
-> ((NextElem (Input rpc) -> m ()) -> m r) -> m (Output rpc, r)
forall a b. (a -> b) -> a -> b
$ \NextElem (Input rpc) -> m ()
send -> (NextElem inp -> m ()) -> m r
k (NextElem ByteString -> m ()
NextElem (Input rpc) -> m ()
send (NextElem ByteString -> m ())
-> (NextElem inp -> NextElem ByteString) -> NextElem inp -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (inp -> ByteString) -> NextElem inp -> NextElem ByteString
forall a b. (a -> b) -> NextElem a -> NextElem b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap inp -> ByteString
forall a. Binary a => a -> ByteString
encode)
    (, r) <$> decodeOrThrow out

-- | Wrapper for 'IO.clientStreaming_' that handles binary serialization
clientStreaming_ :: forall inp out rpc m.
     ( Binary inp, Input  rpc ~ Lazy.ByteString
     , Binary out, Output rpc ~ Lazy.ByteString
     , MonadIO m
     )
  => Connection
  -> ClientHandler' ClientStreaming (ReaderT Connection m) rpc
  -> (   (NextElem inp -> m ())
       -> m ()
     )
  -> m out
clientStreaming_ :: forall {k} inp out (rpc :: k) (m :: * -> *).
(Binary inp, Input rpc ~ ByteString, Binary out,
 Output rpc ~ ByteString, MonadIO m) =>
Connection
-> ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
-> ((NextElem inp -> m ()) -> m ())
-> m out
clientStreaming_ Connection
conn ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
h (NextElem inp -> m ()) -> m ()
k = (out, ()) -> out
forall a b. (a, b) -> a
fst ((out, ()) -> out) -> m (out, ()) -> m out
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Connection
-> ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
-> ((NextElem inp -> m ()) -> m ())
-> m (out, ())
forall {k} inp out (rpc :: k) (m :: * -> *) r.
(Binary inp, Input rpc ~ ByteString, Binary out,
 Output rpc ~ ByteString, MonadIO m) =>
Connection
-> ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
-> ((NextElem inp -> m ()) -> m r)
-> m (out, r)
clientStreaming Connection
conn ClientHandler' 'ClientStreaming (ReaderT Connection m) rpc
h (NextElem inp -> m ()) -> m ()
k

-- | Wrapper for 'IO.serverStreaming' that binary serialization
serverStreaming :: forall inp out rpc m r.
     ( Binary inp, Input  rpc ~ Lazy.ByteString
     , Binary out, Output rpc ~ Lazy.ByteString
     , MonadIO m
     )
  => Connection
  -> ClientHandler' ServerStreaming (ReaderT Connection m) rpc
  -> inp
  -> (    m (NextElem out)
       -> m r
     )
  -> m r
serverStreaming :: forall {k} inp out (rpc :: k) (m :: * -> *) r.
(Binary inp, Input rpc ~ ByteString, Binary out,
 Output rpc ~ ByteString, MonadIO m) =>
Connection
-> ClientHandler' 'ServerStreaming (ReaderT Connection m) rpc
-> inp
-> (m (NextElem out) -> m r)
-> m r
serverStreaming Connection
conn ClientHandler' 'ServerStreaming (ReaderT Connection m) rpc
h inp
inp m (NextElem out) -> m r
k =
    Connection
-> ClientHandler' 'ServerStreaming (ReaderT Connection m) rpc
-> Input rpc
-> (m (NextElem (Output rpc)) -> m r)
-> m r
forall {k} (rpc :: k) (m :: * -> *) r.
MonadIO m =>
Connection
-> ClientHandler' 'ServerStreaming (ReaderT Connection m) rpc
-> Input rpc
-> (m (NextElem (Output rpc)) -> m r)
-> m r
IO.serverStreaming Connection
conn ClientHandler' 'ServerStreaming (ReaderT Connection m) rpc
h (inp -> ByteString
forall a. Binary a => a -> ByteString
encode inp
inp) ((m (NextElem (Output rpc)) -> m r) -> m r)
-> (m (NextElem (Output rpc)) -> m r) -> m r
forall a b. (a -> b) -> a -> b
$ \m (NextElem (Output rpc))
recv ->
      m (NextElem out) -> m r
k ((ByteString -> m out) -> NextElem ByteString -> m (NextElem out)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NextElem a -> f (NextElem b)
traverse ByteString -> m out
forall (m :: * -> *) a. (MonadIO m, Binary a) => ByteString -> m a
decodeOrThrow (NextElem ByteString -> m (NextElem out))
-> m (NextElem ByteString) -> m (NextElem out)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m (NextElem ByteString)
m (NextElem (Output rpc))
recv)

-- | Wrapper for 'IO.biDiStreaming' that handles binary serialization
biDiStreaming :: forall inp out rpc m r.
     ( Binary inp, Input  rpc ~ Lazy.ByteString
     , Binary out, Output rpc ~ Lazy.ByteString
     , MonadIO m
     )
  => Connection
  -> ClientHandler' BiDiStreaming (ReaderT Connection m) rpc
  -> (    (NextElem inp -> m ())
       -> m (NextElem out)
       -> m r
     )
  -> m r
biDiStreaming :: forall {k} inp out (rpc :: k) (m :: * -> *) r.
(Binary inp, Input rpc ~ ByteString, Binary out,
 Output rpc ~ ByteString, MonadIO m) =>
Connection
-> ClientHandler' 'BiDiStreaming (ReaderT Connection m) rpc
-> ((NextElem inp -> m ()) -> m (NextElem out) -> m r)
-> m r
biDiStreaming Connection
conn ClientHandler' 'BiDiStreaming (ReaderT Connection m) rpc
h (NextElem inp -> m ()) -> m (NextElem out) -> m r
k =
    Connection
-> ClientHandler' 'BiDiStreaming (ReaderT Connection m) rpc
-> ((NextElem (Input rpc) -> m ())
    -> m (NextElem (Output rpc)) -> m r)
-> m r
forall {k} (rpc :: k) (m :: * -> *) r.
MonadIO m =>
Connection
-> ClientHandler' 'BiDiStreaming (ReaderT Connection m) rpc
-> ((NextElem (Input rpc) -> m ())
    -> m (NextElem (Output rpc)) -> m r)
-> m r
IO.biDiStreaming Connection
conn ClientHandler' 'BiDiStreaming (ReaderT Connection m) rpc
h (((NextElem (Input rpc) -> m ())
  -> m (NextElem (Output rpc)) -> m r)
 -> m r)
-> ((NextElem (Input rpc) -> m ())
    -> m (NextElem (Output rpc)) -> m r)
-> m r
forall a b. (a -> b) -> a -> b
$ \NextElem (Input rpc) -> m ()
send m (NextElem (Output rpc))
recv ->
      (NextElem inp -> m ()) -> m (NextElem out) -> m r
k (NextElem ByteString -> m ()
NextElem (Input rpc) -> m ()
send (NextElem ByteString -> m ())
-> (NextElem inp -> NextElem ByteString) -> NextElem inp -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (inp -> ByteString) -> NextElem inp -> NextElem ByteString
forall a b. (a -> b) -> NextElem a -> NextElem b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap inp -> ByteString
forall a. Binary a => a -> ByteString
encode)
        ((ByteString -> m out) -> NextElem ByteString -> m (NextElem out)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NextElem a -> f (NextElem b)
traverse ByteString -> m out
forall (m :: * -> *) a. (MonadIO m, Binary a) => ByteString -> m a
decodeOrThrow (NextElem ByteString -> m (NextElem out))
-> m (NextElem ByteString) -> m (NextElem out)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m (NextElem ByteString)
m (NextElem (Output rpc))
recv)