content: module Implementations where
  
  import qualified Control.Concurrent.Chan.Unagi as U
  import qualified Control.Concurrent.Chan.Unagi.Unboxed as UU
  import qualified Control.Concurrent.Chan.Unagi.Bounded as UB
  import qualified Control.Concurrent.Chan.Unagi.NoBlocking as UN
  import qualified Control.Concurrent.Chan.Unagi.NoBlocking.Unboxed as UNU
  import Control.Concurrent(yield, threadDelay)
  
  type Implementation inc outc a = (IO (inc a, outc a), inc a -> a -> IO (), outc a -> IO a, inc a -> IO (outc a))
  
  unagiImpl , unagiTryReadImpl , unagiTryReadBlockingImpl :: Implementation U.InChan U.OutChan a
  unagiImpl =  (U.newChan, U.writeChan, U.readChan, U.dupChan)
  unagiTryReadImpl =  (U.newChan, U.writeChan, u_trying_readChan, U.dupChan)
  unagiTryReadBlockingImpl =  (U.newChan, U.writeChan, u_trying_readChan_blocking, U.dupChan)
  
  unboxedUnagiImpl , unboxedUnagiTryReadImpl, unboxedUnagiTryReadBlockingImpl :: (UU.UnagiPrim a)=> Implementation UU.InChan UU.OutChan a
  unboxedUnagiImpl = (UU.newChan, UU.writeChan, UU.readChan, UU.dupChan)
  unboxedUnagiTryReadImpl = (UU.newChan, UU.writeChan, uu_trying_readChan, UU.dupChan)
  unboxedUnagiTryReadBlockingImpl = (UU.newChan, UU.writeChan, uu_trying_readChan_blocking, UU.dupChan)
  
  unagiBoundedImpl , unagiBoundedTryReadImpl, unagiBoundedTryReadBlockingImpl :: Int -> Implementation UB.InChan UB.OutChan a
  unagiBoundedImpl n =  (UB.newChan n, UB.writeChan, UB.readChan, UB.dupChan)
  unagiBoundedTryReadImpl n =  (UB.newChan n, UB.writeChan, ub_trying_readChan, UB.dupChan)
  unagiBoundedTryReadBlockingImpl n =  (UB.newChan n, UB.writeChan, ub_trying_readChan_blocking, UB.dupChan)
  
  -- We use our yield "blocking" readChan here, and below:
  unagiNoBlockingImpl :: Implementation UN.InChan UN.OutChan a
  unagiNoBlockingImpl =  (UN.newChan, UN.writeChan, UN.readChan yield, UN.dupChan)
  
  unagiNoBlockingUnboxedImpl :: (UU.UnagiPrim a)=> Implementation UNU.InChan UNU.OutChan a
  unagiNoBlockingUnboxedImpl =  (UNU.newChan, UNU.writeChan, UNU.readChan yield, UNU.dupChan)
  
  -- These have same semantics as corresponding `readChan`, so this is an easy
  -- way to do smoke tests of `tryReadChan`:
  uu_trying_readChan :: (UU.UnagiPrim a)=> UU.OutChan a -> IO a
  uu_trying_readChan oc = do
      (e,_) <- UU.tryReadChan oc
      let go = UU.tryRead e >>= maybe (threadDelay 1000 >> go) return
      go
  
  u_trying_readChan :: U.OutChan a -> IO a
  u_trying_readChan oc = do
      (e,_) <- U.tryReadChan oc
      let go = U.tryRead e >>= maybe (threadDelay 1000 >> go) return
      go
  
  ub_trying_readChan :: UB.OutChan a -> IO a
  ub_trying_readChan oc = do
      (e,_) <- UB.tryReadChan oc
      let go = UB.tryRead e >>= maybe (threadDelay 1000 >> go) return
      go
  
  -- And we want to test the blocking action of tryReadChan as well:
  uu_trying_readChan_blocking :: (UU.UnagiPrim a)=> UU.OutChan a -> IO a
  uu_trying_readChan_blocking oc = UU.tryReadChan oc >>= snd
  
  u_trying_readChan_blocking :: U.OutChan a -> IO a
  u_trying_readChan_blocking oc = U.tryReadChan oc >>= snd
  
  ub_trying_readChan_blocking :: UB.OutChan a -> IO a
  ub_trying_readChan_blocking oc = UB.tryReadChan oc >>= snd
  
  