module Next.Producer.State
  (
    {- * State actions -} null, head, push, pop,
  )
  where

import Essentials
import Next.Interface
import Next.Producer.Type

import Control.Monad.Trans.State.Strict (StateT (StateT))
import SupplyChain ((>->), Referral (Referral))

import qualified Control.Monad.Trans.State.Strict as State
import qualified Data.Foldable as Foldable
import qualified Next.Pipe as Pipe
import qualified SupplyChain.Vendor as Vendor

{-| Test whether the state is an empty stream -}
null :: forall action item. Monad action =>
    StateT (Producer action item) action Bool
null :: forall (action :: * -> *) item.
Monad action =>
StateT (Producer action item) action Bool
null = forall (action :: * -> *) item.
Monad action =>
StateT (Producer action item) action (Step item)
head forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> forall (t :: * -> *) a. Foldable t => t a -> Bool
Foldable.null

{-| Peek at the first item in the stream state -}
head :: forall action item. Monad action =>
    StateT (Producer action item) action (Step item)
head :: forall (action :: * -> *) item.
Monad action =>
StateT (Producer action item) action (Step item)
head = forall (action :: * -> *) item.
Monad action =>
StateT (Producer action item) action (Step item)
pop forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Step item
x -> forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ forall (up :: * -> *) (action :: * -> *) item.
Monad action =>
item -> StateT (ProducerPlus up action item) action ()
push Step item
x forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Step item
x

{-| Add an item to the front of the stream state -}
push :: forall up action item. Monad action =>
    item -> StateT (ProducerPlus up action item) action ()
push :: forall (up :: * -> *) (action :: * -> *) item.
Monad action =>
item -> StateT (ProducerPlus up action item) action ()
push item
x = forall (m :: * -> *) s. Monad m => (s -> s) -> StateT s m ()
State.modify' (forall (up :: * -> *) (middle :: * -> *) (action :: * -> *)
       (down :: * -> *).
Vendor up middle action
-> Vendor middle down action -> Vendor up down action
>-> forall item (action :: * -> *) (up :: * -> *).
Job up action item -> PipePlus up action item item
Pipe.cons (forall (f :: * -> *) a. Applicative f => a -> f a
pure item
x))

{- | Take the first item from the stream -}
pop :: forall action item. Monad action =>
    StateT (Producer action item) action (Step item)
pop :: forall (action :: * -> *) item.
Monad action =>
StateT (Producer action item) action (Step item)
pop = forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
StateT \Producer action item
xs ->
    forall (action :: * -> *) (down :: * -> *) product.
Monad action =>
Vendor (Const Void) down action
-> down product
-> action (Referral (Const Void) down action product)
Vendor.run Producer action item
xs forall item (interface :: * -> *).
TerminableStream item interface =>
interface (Step item)
next forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(Referral Step item
s Producer action item
v) -> (Step item
s, Producer action item
v)