-- | Elements in a stream (without metadata)
--
-- Intended for qualified import.
--
-- > import Network.GRPC.Common.NextElem qualified as NextElem
--
-- "Network.GRPC.Common" (intended for unqualified import) exports
-- @NextElem(..)@, but none of the operations on 'NextElem'.
module Network.GRPC.Common.NextElem (
    -- * Conversion
    toStreamElem
    -- * Iteration
  , mapM_
  , forM_
  , whileNext_
  , collect
  ) where

import Prelude hiding (mapM_)

import Control.Monad.State (StateT, execStateT, lift, modify)

import Network.GRPC.Common.StreamElem (StreamElem(..))
import Network.GRPC.Spec (NextElem(..))

{-------------------------------------------------------------------------------
  Conversion
-------------------------------------------------------------------------------}

toStreamElem :: b -> NextElem a -> StreamElem b a
toStreamElem :: forall b a. b -> NextElem a -> StreamElem b a
toStreamElem b
b NextElem a
NoNextElem   = b -> StreamElem b a
forall b a. b -> StreamElem b a
NoMoreElems b
b
toStreamElem b
_ (NextElem a
a) = a -> StreamElem b a
forall b a. a -> StreamElem b a
StreamElem a
a

{-------------------------------------------------------------------------------
  Iteration
-------------------------------------------------------------------------------}

-- | Invoke the callback for each element, and then once more with 'NoNextElem'
--
-- >    mapM_ f [1,2,3]
-- > == do f (NextElem 1)
-- >       f (NextElem 2)
-- >       f (NextElem 3)
-- >       f NoNextElem
mapM_ :: forall m a. Monad m => (NextElem a -> m ()) -> [a] -> m ()
mapM_ :: forall (m :: * -> *) a.
Monad m =>
(NextElem a -> m ()) -> [a] -> m ()
mapM_ NextElem a -> m ()
f = [a] -> m ()
go
  where
    go :: [a] -> m ()
    go :: [a] -> m ()
go []     = NextElem a -> m ()
f NextElem a
forall a. NextElem a
NoNextElem
    go (a
x:[a]
xs) = NextElem a -> m ()
f (a -> NextElem a
forall a. a -> NextElem a
NextElem a
x) m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [a] -> m ()
go [a]
xs

-- | Like 'mapM_', but with the arguments in opposite order
forM_ :: Monad m => [a] -> (NextElem a -> m ()) -> m ()
forM_ :: forall (m :: * -> *) a.
Monad m =>
[a] -> (NextElem a -> m ()) -> m ()
forM_ = ((NextElem a -> m ()) -> [a] -> m ())
-> [a] -> (NextElem a -> m ()) -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip (NextElem a -> m ()) -> [a] -> m ()
forall (m :: * -> *) a.
Monad m =>
(NextElem a -> m ()) -> [a] -> m ()
mapM_

-- | Invoke a function on each 'NextElem', until 'NoNextElem'
--
-- See also 'collect'.
whileNext_ :: forall m a. Monad m => m (NextElem a) -> (a -> m ()) -> m ()
whileNext_ :: forall (m :: * -> *) a.
Monad m =>
m (NextElem a) -> (a -> m ()) -> m ()
whileNext_ m (NextElem a)
f a -> m ()
g = m ()
go
  where
    go :: m ()
    go :: m ()
go = do
        ma <- m (NextElem a)
f
        case ma of
          NextElem a
NoNextElem -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
          NextElem a
a -> a -> m ()
g a
a m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> m ()
go

-- | Invoke the callback until it returns 'NoNextElem', collecting results
collect :: forall m a. Monad m => m (NextElem a) -> m [a]
collect :: forall (m :: * -> *) a. Monad m => m (NextElem a) -> m [a]
collect m (NextElem a)
f =
    [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> m [a] -> m [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (StateT [a] m () -> [a] -> m [a])
-> [a] -> StateT [a] m () -> m [a]
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT [a] m () -> [a] -> m [a]
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT [] StateT [a] m ()
aux
  where
    aux :: StateT [a] m ()
    aux :: StateT [a] m ()
aux = StateT [a] m (NextElem a)
-> (a -> StateT [a] m ()) -> StateT [a] m ()
forall (m :: * -> *) a.
Monad m =>
m (NextElem a) -> (a -> m ()) -> m ()
whileNext_ (m (NextElem a) -> StateT [a] m (NextElem a)
forall (m :: * -> *) a. Monad m => m a -> StateT [a] m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m (NextElem a)
f) ((a -> StateT [a] m ()) -> StateT [a] m ())
-> (a -> StateT [a] m ()) -> StateT [a] m ()
forall a b. (a -> b) -> a -> b
$ ([a] -> [a]) -> StateT [a] m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (([a] -> [a]) -> StateT [a] m ())
-> (a -> [a] -> [a]) -> a -> StateT [a] m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (:)