never executed always true always false
    1 {-# LANGUAGE Strict #-}
    2 
    3 -- | Utilities for exception safe message boxes.
    4 --
    5 -- This provides a wrapper around "UnliftIO.MessageBox.Class" instances
    6 -- to catch 'SomeException' in all methods like 'deliver' and 'receive'.
    7 module UnliftIO.MessageBox.CatchAll
    8   ( CatchAllArg (..),
    9     CatchAllBox (..),
   10     CatchAllInput (..),
   11   )
   12 where
   13 
   14 import UnliftIO.MessageBox.Util.Future (Future (Future))
   15 import UnliftIO.MessageBox.Class
   16   ( IsInput (..),
   17     IsMessageBox (..),
   18     IsMessageBoxArg (..),
   19   )
   20 import UnliftIO (SomeException, liftIO, try)
   21 import UnliftIO.Concurrent (threadDelay)
   22 
   23 -- | A wrapper around values that are instances
   24 -- of 'IsMessageBoxArg'. The factory wraps
   25 -- the result of the delegated 'newMessageBox'
   26 -- invocation into a 'CatchAllBox'.
   27 newtype CatchAllArg cfg = CatchAllArg cfg
   28   deriving stock (Eq, Ord, Show)
   29 
   30 -- | A wrapper around values that are instances
   31 -- of 'IsMessageBox'.
   32 --
   33 -- The 'Input' type will be wrapped using
   34 -- 'CatchAllInput'.
   35 newtype CatchAllBox box a = CatchAllBox (box a)
   36 
   37 -- | A wrapper around values that are instances
   38 -- of 'IsInput'.
   39 newtype CatchAllInput i a = CatchAllInput (i a)
   40 
   41 instance IsMessageBoxArg cfg => IsMessageBoxArg (CatchAllArg cfg) where
   42   type MessageBox (CatchAllArg cfg) = CatchAllBox (MessageBox cfg)
   43   {-# INLINE newMessageBox #-}
   44   newMessageBox (CatchAllArg !cfg) = CatchAllBox <$> newMessageBox cfg
   45   getConfiguredMessageLimit (CatchAllArg !cfg) =
   46     getConfiguredMessageLimit cfg
   47 
   48 instance IsMessageBox box => IsMessageBox (CatchAllBox box) where
   49   type Input (CatchAllBox box) = CatchAllInput (Input box)
   50   {-# INLINE newInput #-}
   51   newInput (CatchAllBox !b) =
   52     CatchAllInput <$> newInput b
   53   {-# INLINE receive #-}
   54   receive (CatchAllBox !box) =
   55     try @_ @SomeException
   56       (receive box)
   57       >>= \case
   58         Left _e -> liftIO (print _e) >> return Nothing
   59         Right r -> return r
   60   {-# INLINE receiveAfter #-}
   61   -- | Call the wrapped 'receiveAfter' and catch all sync exceptions.
   62   -- 
   63   -- When an exception is caught return 'Nothing'.
   64   receiveAfter (CatchAllBox !box) !t =
   65     try @_ @SomeException
   66       (receiveAfter box t)
   67       >>= \case
   68         Left _e -> liftIO (print _e) >> pure Nothing
   69         Right r -> return r
   70   {-# INLINE tryReceive #-}
   71   tryReceive (CatchAllBox !box) =
   72     try @_ @SomeException
   73       (tryReceive box)
   74       >>= \case
   75         Left _e ->
   76           liftIO (print _e)
   77             >> return
   78               ( Future
   79                   ( do
   80                       -- suspense...
   81                       threadDelay 1000
   82                       -- ... anyway, the truth is: there is no spoon.
   83                       return Nothing
   84                   )
   85               )
   86         Right r -> return r
   87 
   88 instance (IsInput i) => IsInput (CatchAllInput i) where
   89   {-# INLINE deliver #-}
   90   deliver (CatchAllInput !i) !msg =
   91     try @_ @SomeException
   92       (deliver i msg)
   93       >>= \case
   94         Left _e -> liftIO (print _e) >> return False
   95         Right r -> return r