{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE Safe #-}
-------------------------------------------------------------------------------
-- |
-- Module      :  BroadcastChan.Throw
-- Copyright   :  (C) 2014-2018 Merijn Verstraaten
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Merijn Verstraaten <merijn@inconsistent.nl>
-- Stability   :  experimental
-- Portability :  haha
--
-- This module is identical to "BroadcastChan", but with
-- @BroadcastChan.@'BroadcastChan.writeBChan' and
-- @BroadcastChan.@'BroadcastChan.readBChan' replaced with versions that throw
-- an exception, rather than returning results that the user has to inspect to
-- check for success.
-------------------------------------------------------------------------------
module BroadcastChan.Throw
    ( BChanError(..)
    , readBChan
    , writeBChan
    -- * Re-exports from "BroadcastChan"
    -- ** Datatypes
    , BroadcastChan
    , Direction(..)
    , In
    , Out
    -- ** Construction
    , newBroadcastChan
    , newBChanListener
    -- ** Basic Operations
    , closeBChan
    , isClosedBChan
    , getBChanContents
    -- ** Parallel processing
    , Action(..)
    , Handler(..)
    , parMapM_
    , parFoldMap
    , parFoldMapM
    -- ** Foldl combinators
    -- | Combinators for use with Tekmo's @foldl@ package.
    , foldBChan
    , foldBChanM
    ) where

import Control.Monad (when)
import Control.Exception (Exception, throwIO)
import Data.Typeable (Typeable)

import BroadcastChan hiding (writeBChan, readBChan)
import qualified BroadcastChan as Internal

-- | Exception type for 'BroadcastChan' operations.
data BChanError
    = WriteFailed   -- ^ Attempted to write to closed 'BroadcastChan'
    | ReadFailed    -- ^ Attempted to read from an empty closed 'BroadcastChan'
    deriving (BChanError -> BChanError -> Bool
(BChanError -> BChanError -> Bool)
-> (BChanError -> BChanError -> Bool) -> Eq BChanError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BChanError -> BChanError -> Bool
$c/= :: BChanError -> BChanError -> Bool
== :: BChanError -> BChanError -> Bool
$c== :: BChanError -> BChanError -> Bool
Eq, ReadPrec [BChanError]
ReadPrec BChanError
Int -> ReadS BChanError
ReadS [BChanError]
(Int -> ReadS BChanError)
-> ReadS [BChanError]
-> ReadPrec BChanError
-> ReadPrec [BChanError]
-> Read BChanError
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [BChanError]
$creadListPrec :: ReadPrec [BChanError]
readPrec :: ReadPrec BChanError
$creadPrec :: ReadPrec BChanError
readList :: ReadS [BChanError]
$creadList :: ReadS [BChanError]
readsPrec :: Int -> ReadS BChanError
$creadsPrec :: Int -> ReadS BChanError
Read, Int -> BChanError -> ShowS
[BChanError] -> ShowS
BChanError -> String
(Int -> BChanError -> ShowS)
-> (BChanError -> String)
-> ([BChanError] -> ShowS)
-> Show BChanError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BChanError] -> ShowS
$cshowList :: [BChanError] -> ShowS
show :: BChanError -> String
$cshow :: BChanError -> String
showsPrec :: Int -> BChanError -> ShowS
$cshowsPrec :: Int -> BChanError -> ShowS
Show, Typeable)

instance Exception BChanError

-- | Like 'Internal.readBChan', but throws a 'ReadFailed' exception when
-- reading from a closed and empty 'BroadcastChan'.
readBChan :: BroadcastChan Out a -> IO a
readBChan :: BroadcastChan Out a -> IO a
readBChan BroadcastChan Out a
ch = do
    Maybe a
result <- BroadcastChan Out a -> IO (Maybe a)
forall (m :: * -> *) a.
MonadIO m =>
BroadcastChan Out a -> m (Maybe a)
Internal.readBChan BroadcastChan Out a
ch
    case Maybe a
result of
        Maybe a
Nothing -> BChanError -> IO a
forall e a. Exception e => e -> IO a
throwIO BChanError
ReadFailed
        Just a
x -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
{-# INLINE readBChan #-}

-- | Like 'Internal.writeBChan', but throws a 'WriteFailed' exception when
-- writing to closed 'BroadcastChan'.
writeBChan :: BroadcastChan In a -> a -> IO ()
writeBChan :: BroadcastChan In a -> a -> IO ()
writeBChan BroadcastChan In a
ch a
val = do
    Bool
success <- BroadcastChan In a -> a -> IO Bool
forall (m :: * -> *) a.
MonadIO m =>
BroadcastChan In a -> a -> m Bool
Internal.writeBChan BroadcastChan In a
ch a
val
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
success) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ BChanError -> IO ()
forall e a. Exception e => e -> IO a
throwIO BChanError
WriteFailed
{-# INLINE writeBChan #-}