{-# LANGUAGE UnicodeSyntax #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Data.Timeout ( TimedOut(..), TimeoutUnit(..), timeoutUnitNanos, Timeout(..), (#), (#>), (#<), instantly ) where import Data.Typeable (Typeable) import Data.Ix (Ix) import Data.Word (Word64) import Data.List (intercalate) import Control.Exception (Exception) -- | Exception that is raised when an operation times out. -- Not used by the package itself, it is here so that users don't need to -- roll their own exception type every time. data TimedOut = TimedOut deriving (Typeable, Eq, Show) instance Exception TimedOut -- | Timeout unit. data TimeoutUnit = NanoSecond | MicroSecond | MilliSecond | Second | Minute | Hour | Day | Week deriving (Typeable, Eq, Ord, Bounded, Ix, Enum) -- | Amount of nanoseconds in a timeout unit. timeoutUnitNanos ∷ TimeoutUnit → Word64 timeoutUnitNanos NanoSecond = 1 timeoutUnitNanos MicroSecond = 1000 timeoutUnitNanos MilliSecond = 1000000 timeoutUnitNanos Second = 1000000000 timeoutUnitNanos Minute = 60 * 1000000000 timeoutUnitNanos Hour = 60 * 60 * 1000000000 timeoutUnitNanos Day = 24 * 60 * 60 * 1000000000 timeoutUnitNanos Week = 7 * 24 * 60 * 60 * 1000000000 {-# INLINE timeoutUnitNanos #-} -- | Timeout in nanoseconds. newtype Timeout = Timeout Word64 deriving (Typeable, Eq, Ord, Bounded, Ix, Enum, Num, Real, Integral) infix 9 # infix 8 #>, #< -- | Convert the given number of timeout units to 'Timeout'. (#) ∷ Word64 → TimeoutUnit → Timeout n # u = Timeout $ n * timeoutUnitNanos u {-# INLINE (#) #-} -- | Extract number of units (rounding up). (#>) ∷ Timeout → TimeoutUnit → Word64 (Timeout tt) #> u = if r == 0 then q else q + 1 where (q, r) = tt `quotRem` timeoutUnitNanos u {-# INLINE (#>) #-} -- | Extract number of units (rounding down). (#<) ∷ Timeout → TimeoutUnit → Word64 (Timeout tt) #< u = tt `quot` timeoutUnitNanos u {-# INLINE (#<) #-} timeoutUnitAbbr ∷ TimeoutUnit → String timeoutUnitAbbr NanoSecond = "ns" timeoutUnitAbbr MicroSecond = "us" timeoutUnitAbbr MilliSecond = "ms" timeoutUnitAbbr Second = "s" timeoutUnitAbbr Minute = "m" timeoutUnitAbbr Hour = "h" timeoutUnitAbbr Day = "d" timeoutUnitAbbr Week = "w" instance Show Timeout where show (Timeout tt) = if null ss then "instant" else intercalate " " (reverse ss) where ss = snd $ ($ enumFrom NanoSecond) $ (`foldr` (tt, [])) $ \u (t, ss') → let (q, r) = t `quotRem` timeoutUnitNanos u abbr = timeoutUnitAbbr u in (r, if q == 0 then ss' else (show q ++ " " ++ abbr) : ss') -- | Zero timeout. The event in question should occur immediately. instantly ∷ Timeout instantly = 0 # NanoSecond {-# INLINE instantly #-}