packages feed

posix-api-0.3.0.0: src/Posix/Poll/Types.hsc

{-# language BangPatterns #-}
{-# language BinaryLiterals #-}
{-# language DataKinds #-}
{-# language DerivingStrategies #-}
{-# language DuplicateRecordFields #-}
{-# language GADTSyntax #-}
{-# language GeneralizedNewtypeDeriving #-}
{-# language KindSignatures #-}
{-# language NamedFieldPuns #-}
{-# language TypeApplications #-}
{-# language MagicHash #-}
{-# language UnboxedTuples #-}
{-# language PolyKinds #-}
{-# language TypeInType #-}

-- This is needed because hsc2hs does not currently handle ticked
-- promoted data constructors correctly.
{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-}

#define _GNU_SOURCE
#include <poll.h>
#include "custom.h"

-- | All of the data constructors provided by this module are unsafe.
--   Only use them if you really know what you are doing.
module Posix.Poll.Types
  ( PollFd(..)
  , Exchange(..)
  , input
  , output
  , error
  , hangup
  , invalid
  , isSubeventOf
  ) where

import Prelude hiding (truncate,error)

import Data.Bits ((.|.),(.&.))
import Data.Word (Word8,Word16,Word32,Word64)
import Data.Primitive (Prim(..))
import Foreign.C.Types (CInt(..),CShort)
import Foreign.Storable (Storable(..))
import GHC.Ptr (Ptr(..))
import GHC.Exts (RealWorld,Int(I##),Int##,(+##),(*##))
import System.Posix.Types (Fd(..))

import qualified Data.Kind
import qualified Data.Primitive as PM

data PollFd = PollFd
  { descriptor :: !Fd
    -- ^ The @fd@ field of @struct pollfd@
  , request :: !(Event Request)
    -- ^ The @events@ field of @struct pollfd@
  , response :: !(Event Response)
    -- ^ The @revents@ field of @struct pollfd@
  }

newtype Event :: Exchange -> Data.Kind.Type where
  Event :: CShort -> Event e
  deriving newtype (Eq,Storable,Prim)

instance Semigroup (Event e) where
  Event a <> Event b = Event (a .|. b)

instance Monoid (Event e) where
  mempty = Event 0

data Exchange = Request | Response

instance Storable PollFd where
  sizeOf _ = #{size struct pollfd}
  alignment _ = alignment (undefined :: CInt)
  peek ptr = do
    descriptor <- #{peek struct pollfd, fd} ptr
    request <- #{peek struct pollfd, events} ptr
    response <- #{peek struct pollfd, revents} ptr
    let !pollfd = PollFd{descriptor,request,response}
    pure pollfd
  poke ptr PollFd{descriptor,request,response} = do
    #{poke struct pollfd, fd} ptr descriptor
    #{poke struct pollfd, events} ptr request
    #{poke struct pollfd, revents} ptr response

unI :: Int -> Int##
unI (I## i) = i

instance Prim PollFd where
  sizeOf## _ = unI #{size struct pollfd}
  alignment## _ = alignment## (undefined :: CInt)
  indexByteArray## arr i = PollFd
    { descriptor = #{indexByteArrayHash struct pollfd, fd} arr i
    , request = #{indexByteArrayHash struct pollfd, events} arr i
    , response = #{indexByteArrayHash struct pollfd, revents} arr i
    }
  writeByteArray## arr i PollFd{descriptor,request,response} s0 = case #{writeByteArrayHash struct pollfd, fd} arr i descriptor s0 of
    s1 -> case #{writeByteArrayHash struct pollfd, events} arr i request s1 of
      s2 -> #{writeByteArrayHash struct pollfd, revents} arr i response s2
  readByteArray## arr i s0 = case #{readByteArrayHash struct pollfd, fd} arr i s0 of
    (## s1, descriptor ##) -> case #{readByteArrayHash struct pollfd, events} arr i s1 of
      (## s2, request ##) -> case #{readByteArrayHash struct pollfd, revents} arr i s2 of
        (## s3, response ##) -> (## s3, PollFd{descriptor,request,response} ##)
  setByteArray## = PM.defaultSetByteArray##
  indexOffAddr## arr i = PollFd
    { descriptor = #{indexOffAddrHash struct pollfd, fd} arr i
    , request = #{indexOffAddrHash struct pollfd, events} arr i
    , response = #{indexOffAddrHash struct pollfd, revents} arr i
    }
  writeOffAddr## arr i PollFd{descriptor,request,response} s0 = case #{writeOffAddrHash struct pollfd, fd} arr i descriptor s0 of
    s1 -> case #{writeOffAddrHash struct pollfd, events} arr i request s1 of
      s2 -> #{writeOffAddrHash struct pollfd, revents} arr i response s2
  readOffAddr## arr i s0 = case #{readOffAddrHash struct pollfd, fd} arr i s0 of
    (## s1, fdVal ##) -> case #{readOffAddrHash struct pollfd, events} arr i s1 of
      (## s2, eventsVal ##) -> case #{readOffAddrHash struct pollfd, revents} arr i s2 of
        (## s3, reventsVal ##) -> (## s3, PollFd fdVal eventsVal reventsVal ##)
  setOffAddr## = PM.defaultSetOffAddr##

-- | The @POLLIN@ event.
input :: Event e
input = Event #{const POLLIN}

-- | The @POLLOUT@ event.
output :: Event e
output = Event #{const POLLOUT}

-- | The @POLLERR@ event.
error :: Event Response
error = Event #{const POLLERR}

-- | The @POLLHUP@ event.
hangup :: Event Response
hangup = Event #{const POLLHUP}

-- | The @POLLNVAL@ event.
invalid :: Event Response
invalid = Event #{const POLLNVAL}

-- | Is the first argument a subset of the second argument?
isSubeventOf :: Event e -> Event e -> Bool
isSubeventOf (Event a) (Event b) = a .&. b == a