content: module Polysemy.Input.Streaming
    ( -- * Underlying Effect
      module Polysemy.Input
  
      -- * Actions
    , yieldInput
    , yieldRace
    , exhaust
  
      -- * Intepretations
    , runInputViaStream
    , runInputViaInfiniteStream
    ) where
  
  import qualified Control.Concurrent.Async as A
  import           Data.Functor.Of
  import           Data.Void
  import           Polysemy
  import           Polysemy.Final
  import           Polysemy.Input
  import           Polysemy.State
  import qualified Streaming as S
  import qualified Streaming.Prelude as S
  
  
  
  runInputViaStream
      :: S.Stream (Of i) (Sem r) ()
      -> InterpreterFor (Input (Maybe i)) r
  runInputViaStream stream
    = evalState (Just stream)
    . reinterpret ( \Input ->
        get >>= \case
          Nothing -> pure Nothing
          Just s ->
            raise (S.inspect s) >>= \case
              Left () -> pure Nothing
              Right (i :> s') -> do
                put $ Just s'
                pure $ Just i
    )
  
  
  runInputViaInfiniteStream
      :: forall i r
       . S.Stream (Of i) (Sem r) Void
      -> InterpreterFor (Input i) r
  runInputViaInfiniteStream stream
    = evalState stream
    . reinterpret ( \Input -> do
        s <- get
        raise (S.inspect s) >>= \case
          Left g -> absurd g
          Right (i :> s') -> do
            put s'
            pure i
    )
  
  
  yieldRace
      :: Members
          '[ Final IO
           , Input i1
           , Input i2
           ] r
      => S.Stream (S.Of (Either i1 i2)) (Sem r) ()
  yieldRace = do
    z <- S.lift $ withStrategicToFinal $ do
           input1 <- runS input
           input2 <- runS input
           pure $ fmap sequenceEither $ A.race input1 input2
    S.yield z
  
  
  sequenceEither :: Functor f => Either (f a) (f b) -> f (Either a b)
  sequenceEither (Left fa) = Left <$> fa
  sequenceEither (Right fb) = Right <$> fb
  
  
  yieldInput :: Member (Input i) r => S.Stream (Of i) (Sem r) ()
  yieldInput = S.lift input >>= S.yield
  
  
  exhaust :: Member (Input i) r => S.Stream (Of i) (Sem r) a
  exhaust = S.repeatM input
  
  