{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | Unagi-Chan Bounded Transport Instance.
-- 
-- This makes use of a KnownNat parameter to specify the size of the buffer.
-- 
module Control.Churro.Transport.Unagi.Bounded where
    
import Control.Churro.Types
import Control.Churro.Prelude

import Control.Concurrent.Chan.Unagi.Bounded
import Data.Void
import Data.Data (Proxy(..))
import GHC.TypeLits (KnownNat, natVal)

-- $setup
-- 
-- Test Setup
-- 
-- >>> :set -XDataKinds
-- >>> import Control.Churro

data UnagiBounded n a

instance KnownNat n => Transport (UnagiBounded n) where
    data In  (UnagiBounded n) a = ChanIn  (InChan  a)
    data Out (UnagiBounded n) a = ChanOut (OutChan a)
    yank :: Out (UnagiBounded n) a -> IO a
yank (ChanOut c) = OutChan a -> IO a
forall a. OutChan a -> IO a
readChan  OutChan a
c
    yeet :: In (UnagiBounded n) a -> a -> IO ()
yeet (ChanIn  c) = InChan a -> a -> IO ()
forall a. InChan a -> a -> IO ()
writeChan InChan a
c
    flex :: IO (In (UnagiBounded n) a, Out (UnagiBounded n) a)
flex = do 
        (InChan a
i, OutChan a
o) <- Int -> IO (InChan a, OutChan a)
forall a. Int -> IO (InChan a, OutChan a)
newChan (Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
forall k (t :: k). Proxy t
Proxy :: Proxy n)))
        (In (UnagiBounded n) a, Out (UnagiBounded n) a)
-> IO (In (UnagiBounded n) a, Out (UnagiBounded n) a)
forall (m :: * -> *) a. Monad m => a -> m a
return (InChan a -> In (UnagiBounded n) a
forall (n :: Nat) a. InChan a -> In (UnagiBounded n) a
ChanIn InChan a
i, OutChan a -> Out (UnagiBounded n) a
forall (n :: Nat) a. OutChan a -> Out (UnagiBounded n) a
ChanOut OutChan a
o)

type ChurroUnagiBounded a n = Churro a (UnagiBounded n)

-- | Convenience function for running a Churro with a Bounded Unagi-Chan Transport.
-- 
runWaitUnagi :: KnownNat n => ChurroUnagiBounded a n Void Void -> IO a
runWaitUnagi :: ChurroUnagiBounded a n Void Void -> IO a
runWaitUnagi = ChurroUnagiBounded a n Void Void -> IO a
forall (t :: * -> *) a. Transport t => Churro a t Void Void -> IO a
runWait

-- | Convenience function for running a Churro into a List with a Bounded Unagi-Chan Transport.
-- 
-- >>> runWaitListUnagi @10 $ sourceList [1,2,3] >>> arr succ
-- [2,3,4]
runWaitListUnagi :: KnownNat n => ChurroUnagiBounded () n Void o -> IO [o]
runWaitListUnagi :: ChurroUnagiBounded () n Void o -> IO [o]
runWaitListUnagi = ChurroUnagiBounded () n Void o -> IO [o]
forall (t :: * -> *) a b.
(Transport t, Monoid a) =>
Churro a t Void b -> IO [b]
runWaitList

-- A version of processes that mandates the use of a single item buffer for the internal processes.
-- This is useful in order to prevent allocating to processes that are not yet idle.
-- 
processesUnagi :: (Traversable f, Transport t, Monoid a) => f (ChurroUnagiBounded a 1 i o) -> Churro a t i o
processesUnagi :: f (ChurroUnagiBounded a 1 i o) -> Churro a t i o
processesUnagi = f (ChurroUnagiBounded a 1 i o) -> Churro a t i o
forall (f :: * -> *) (t1 :: * -> *) (t2 :: * -> *) a i o.
(Traversable f, Transport t1, Transport t2, Monoid a) =>
f (Churro a t1 i o) -> Churro a t2 i o
processes