{-# LANGUAGE NoImplicitPrelude #-}
-------------------------------------------------------------------------------
-- |
-- Module      :  GHC.IO.Types
-- Copyright   :  (c) Tamar Christina 2018
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  stable
-- Portability :  non-portable
--
-- Abstraction over C Handle types for GHC, Unix wants FD (CInt) while Windows
-- Wants Handle (CIntPtr), so we abstract over them here.
--
-------------------------------------------------------------------------------

module GHC.Internal.Event.Internal.Types
    (
    -- * Event type
      Event
    , evtRead
    , evtWrite
    , evtClose
    , evtNothing
    , eventIs
    -- * Lifetimes
    , Lifetime(..)
    , EventLifetime
    , eventLifetime
    , elLifetime
    , elEvent
    -- * Timeout type
    , Timeout(..)
    ) where

import GHC.Internal.Data.OldList (foldl', filter, intercalate, null)

import GHC.Internal.Data.Bits ((.|.), (.&.))
import GHC.Internal.Data.Semigroup.Internal (stimesMonoid)

import GHC.Internal.Base
import GHC.Internal.Show (Show(..))
import GHC.Internal.Word (Word64)

-- | An I\/O event.
newtype Event = Event Int
    deriving Event -> Event -> Bool
(Event -> Event -> Bool) -> (Event -> Event -> Bool) -> Eq Event
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Event -> Event -> Bool
== :: Event -> Event -> Bool
$c/= :: Event -> Event -> Bool
/= :: Event -> Event -> Bool
Eq -- ^ @since base-4.4.0.0

evtNothing :: Event
evtNothing :: Event
evtNothing = Int -> Event
Event Int
0
{-# INLINE evtNothing #-}

-- | Data is available to be read.
evtRead :: Event
evtRead :: Event
evtRead = Int -> Event
Event Int
1
{-# INLINE evtRead #-}

-- | The file descriptor is ready to accept a write.
evtWrite :: Event
evtWrite :: Event
evtWrite = Int -> Event
Event Int
2
{-# INLINE evtWrite #-}

-- | Another thread closed the file descriptor.
--
-- This event is only meant to be used by @'closeFdWith'@ to signal other
-- threads currently waiting on the same file descriptor that it was closed.
-- It is not meant to be waited on directly and intentionally not exposed
-- in the external interface (only @'evtRead'@ and @'evtWrite'@ are).
evtClose :: Event
evtClose :: Event
evtClose = Int -> Event
Event Int
4
{-# INLINE evtClose #-}

eventIs :: Event -> Event -> Bool
eventIs :: Event -> Event -> Bool
eventIs (Event Int
a) (Event Int
b) = Int
a Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
b Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0

-- | @since base-4.4.0.0
instance Show Event where
    show :: Event -> String
show Event
e = Char
'[' Char -> ShowS
forall a. a -> [a] -> [a]
: (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall a. [a] -> Bool
null) ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
                    [Event
evtRead Event -> ShowS
`so` String
"evtRead",
                     Event
evtWrite Event -> ShowS
`so` String
"evtWrite",
                     Event
evtClose Event -> ShowS
`so` String
"evtClose"]) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"
        where Event
ev so :: Event -> ShowS
`so` String
disp | Event
e Event -> Event -> Bool
`eventIs` Event
ev = String
disp
                           | Bool
otherwise      = String
""

-- | @since base-4.10.0.0
instance Semigroup Event where
    <> :: Event -> Event -> Event
(<>)    = Event -> Event -> Event
evtCombine
    stimes :: forall b. Integral b => b -> Event -> Event
stimes  = b -> Event -> Event
forall b a. (Integral b, Monoid a) => b -> a -> a
stimesMonoid

-- | @since base-4.4.0.0
instance Monoid Event where
    mempty :: Event
mempty  = Event
evtNothing
    mconcat :: [Event] -> Event
mconcat = [Event] -> Event
evtConcat

evtCombine :: Event -> Event -> Event
evtCombine :: Event -> Event -> Event
evtCombine (Event Int
a) (Event Int
b) = Int -> Event
Event (Int
a Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
b)
{-# INLINE evtCombine #-}

evtConcat :: [Event] -> Event
evtConcat :: [Event] -> Event
evtConcat = (Event -> Event -> Event) -> Event -> [Event] -> Event
forall a b. (b -> a -> b) -> b -> [a] -> b
foldl' Event -> Event -> Event
evtCombine Event
evtNothing
{-# INLINE evtConcat #-}

-- | The lifetime of an event registration.
--
-- @since base-4.8.1.0
data Lifetime = OneShot   -- ^ the registration will be active for only one
                          -- event
              | MultiShot -- ^ the registration will trigger multiple times
              deriving ( Int -> Lifetime -> ShowS
[Lifetime] -> ShowS
Lifetime -> String
(Int -> Lifetime -> ShowS)
-> (Lifetime -> String) -> ([Lifetime] -> ShowS) -> Show Lifetime
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Lifetime -> ShowS
showsPrec :: Int -> Lifetime -> ShowS
$cshow :: Lifetime -> String
show :: Lifetime -> String
$cshowList :: [Lifetime] -> ShowS
showList :: [Lifetime] -> ShowS
Show -- ^ @since base-4.8.1.0
                       , Lifetime -> Lifetime -> Bool
(Lifetime -> Lifetime -> Bool)
-> (Lifetime -> Lifetime -> Bool) -> Eq Lifetime
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Lifetime -> Lifetime -> Bool
== :: Lifetime -> Lifetime -> Bool
$c/= :: Lifetime -> Lifetime -> Bool
/= :: Lifetime -> Lifetime -> Bool
Eq   -- ^ @since base-4.8.1.0
                       )

-- | The longer of two lifetimes.
elSupremum :: Lifetime -> Lifetime -> Lifetime
elSupremum :: Lifetime -> Lifetime -> Lifetime
elSupremum Lifetime
OneShot Lifetime
OneShot = Lifetime
OneShot
elSupremum Lifetime
_       Lifetime
_       = Lifetime
MultiShot
{-# INLINE elSupremum #-}

-- | @since base-4.10.0.0
instance Semigroup Lifetime where
    <> :: Lifetime -> Lifetime -> Lifetime
(<>) = Lifetime -> Lifetime -> Lifetime
elSupremum
    stimes :: forall b. Integral b => b -> Lifetime -> Lifetime
stimes = b -> Lifetime -> Lifetime
forall b a. (Integral b, Monoid a) => b -> a -> a
stimesMonoid

-- | @mappend@ takes the longer of two lifetimes.
--
-- @since base-4.8.0.0
instance Monoid Lifetime where
    mempty :: Lifetime
mempty = Lifetime
OneShot

-- | A pair of an event and lifetime
--
-- Here we encode the event in the bottom three bits and the lifetime
-- in the fourth bit.
newtype EventLifetime = EL Int
                      deriving ( Int -> EventLifetime -> ShowS
[EventLifetime] -> ShowS
EventLifetime -> String
(Int -> EventLifetime -> ShowS)
-> (EventLifetime -> String)
-> ([EventLifetime] -> ShowS)
-> Show EventLifetime
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EventLifetime -> ShowS
showsPrec :: Int -> EventLifetime -> ShowS
$cshow :: EventLifetime -> String
show :: EventLifetime -> String
$cshowList :: [EventLifetime] -> ShowS
showList :: [EventLifetime] -> ShowS
Show -- ^ @since base-4.8.0.0
                               , EventLifetime -> EventLifetime -> Bool
(EventLifetime -> EventLifetime -> Bool)
-> (EventLifetime -> EventLifetime -> Bool) -> Eq EventLifetime
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EventLifetime -> EventLifetime -> Bool
== :: EventLifetime -> EventLifetime -> Bool
$c/= :: EventLifetime -> EventLifetime -> Bool
/= :: EventLifetime -> EventLifetime -> Bool
Eq   -- ^ @since base-4.8.0.0
                               )

-- | @since base-4.11.0.0
instance Semigroup EventLifetime where
    EL Int
a <> :: EventLifetime -> EventLifetime -> EventLifetime
<> EL Int
b = Int -> EventLifetime
EL (Int
a Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
b)

-- | @since base-4.8.0.0
instance Monoid EventLifetime where
    mempty :: EventLifetime
mempty = Int -> EventLifetime
EL Int
0

eventLifetime :: Event -> Lifetime -> EventLifetime
eventLifetime :: Event -> Lifetime -> EventLifetime
eventLifetime (Event Int
e) Lifetime
l = Int -> EventLifetime
EL (Int
e Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Lifetime -> Int
forall {a}. Num a => Lifetime -> a
lifetimeBit Lifetime
l)
  where
    lifetimeBit :: Lifetime -> a
lifetimeBit Lifetime
OneShot   = a
0
    lifetimeBit Lifetime
MultiShot = a
8
{-# INLINE eventLifetime #-}

elLifetime :: EventLifetime -> Lifetime
elLifetime :: EventLifetime -> Lifetime
elLifetime (EL Int
x) = if Int
x Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
8 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Lifetime
OneShot else Lifetime
MultiShot
{-# INLINE elLifetime #-}

elEvent :: EventLifetime -> Event
elEvent :: EventLifetime -> Event
elEvent (EL Int
x) = Int -> Event
Event (Int
x Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7)
{-# INLINE elEvent #-}

-- | A type alias for timeouts, specified in nanoseconds.
data Timeout = Timeout {-# UNPACK #-} !Word64
             | Forever
               deriving Int -> Timeout -> ShowS
[Timeout] -> ShowS
Timeout -> String
(Int -> Timeout -> ShowS)
-> (Timeout -> String) -> ([Timeout] -> ShowS) -> Show Timeout
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Timeout -> ShowS
showsPrec :: Int -> Timeout -> ShowS
$cshow :: Timeout -> String
show :: Timeout -> String
$cshowList :: [Timeout] -> ShowS
showList :: [Timeout] -> ShowS
Show -- ^ @since base-4.4.0.0