{- This file is part of time-out.
 -
 - Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
 -
 - ♡ Copying is an act of love. Please copy, reuse and share.
 -
 - The author(s) have dedicated all copyright and related and neighboring
 - rights to this software to the public domain worldwide. This software is
 - distributed without any warranty.
 -
 - You should have received a copy of the CC0 Public Domain Dedication along
 - with this software. If not, see
 - <http://creativecommons.org/publicdomain/zero/1.0/>.
 -}

{-# LANGUAGE MultiParamTypeClasses #-}

-- | A typeclass for monads which can run actions with a time limit.
module Control.Monad.Timeout.Class
    ( Timeout (..)
    , MonadTimeout (..)
    )
where

import Control.Exception (Exception)
import Data.Time.Units (TimeUnit)

-- | Timeout exception. Thrown when an action is executed with a time limit,
-- and the time passes before the action finishes.
data Timeout = Timeout deriving Show

instance Exception Timeout

-- | A class for monads capable of executing computations with a time limit.
-- This class provides a uniform interface to the various possible
-- implementations.
--
-- For example, a trivial implementation may launch a helper thread for each
-- time-limited action. A more scalable implementation, preferred for some
-- cases, may keep a single dedicated thread and reuse it instead of starting
-- new ones.
class (Monad p, Monad m) => MonadTimeout m p where
    -- | Execute an action with a time limit. If the action finishes before the
    -- given time passes, return the value it returned. If the time passes and
    -- the action hasn't finished yet, throw a 'Timeout' exception.
    timeoutThrow :: TimeUnit t => t -> p a -> m a

    -- | Execute an action with a time limit. If the action finishes before the
    -- given time passes, return 'Just' the value it returned. If the time
    -- passes and the action hasn't finished yet, return 'Nothing'.
    timeoutCatch :: TimeUnit t => t -> p a -> m (Maybe a)