{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  GHC.Internal.IO.Device
-- Copyright   :  (c) The University of Glasgow, 1994-2008
-- License     :  see libraries/base/LICENSE
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  internal
-- Portability :  non-portable
--
-- Type classes for I/O providers.
--
-- /The API of this module is unstable and not meant to be consumed by the general public./
-- If you absolutely must depend on it, make sure to use a tight upper
-- bound, e.g., @base < 4.X@ rather than @base < 5@, because the interface can
-- change rapidly without much warning.
--
-----------------------------------------------------------------------------

module GHC.Internal.IO.Device (
        RawIO(..),
        IODevice(..),
        IODeviceType(..),
        SeekMode(..)
    ) where

import GHC.Internal.Base
import GHC.Internal.Word
import GHC.Internal.Arr
import GHC.Internal.Enum
import GHC.Internal.Read
import GHC.Internal.Show
import GHC.Internal.Ptr
import GHC.Internal.Num
import GHC.Internal.IO
import {-# SOURCE #-} GHC.Internal.IO.Exception ( unsupportedOperation )

-- | A low-level I/O provider where the data is bytes in memory.
--   The Word64 offsets currently have no effect on POSIX system or consoles
--   where the implicit behaviour of the C runtime is assumed to move the file
--   pointer on every read/write without needing an explicit seek.
class RawIO a where
  -- | Read up to the specified number of bytes starting from a specified
  -- offset, returning the number of bytes actually read.  This function
  -- should only block if there is no data available.  If there is not enough
  -- data available, then the function should just return the available data.
  -- A return value of zero indicates that the end of the data stream (e.g. end
  -- of file) has been reached.
  read                :: a -> Ptr Word8 -> Word64 -> Int -> IO Int

  -- | Read up to the specified number of bytes starting from a specified
  -- offset, returning the number of bytes actually read, or 'Nothing' if
  -- the end of the stream has been reached.
  readNonBlocking     :: a -> Ptr Word8 -> Word64 -> Int -> IO (Maybe Int)

  -- | Write the specified number of bytes starting at a given offset.
  write               :: a -> Ptr Word8 -> Word64 -> Int -> IO ()

  -- | Write up to the specified number of bytes without blocking starting at a
  -- given offset.  Returns the actual number of bytes written.
  writeNonBlocking    :: a -> Ptr Word8 -> Word64 -> Int -> IO Int


-- | I/O operations required for implementing a 'System.IO.Handle'.
class IODevice a where
  -- | @ready dev write msecs@ returns 'True' if the device has data
  -- to read (if @write@ is 'False') or space to write new data (if
  -- @write@ is 'True').  @msecs@ specifies how long to wait, in
  -- milliseconds.
  --
  ready :: a -> Bool -> Int -> IO Bool

  -- | closes the device.  Further operations on the device should
  -- produce exceptions.
  close :: a -> IO ()

  -- | returns 'True' if the device is a terminal or console.
  isTerminal :: a -> IO Bool
  isTerminal a
_ = Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

  -- | returns 'True' if the device supports 'seek' operations.
  isSeekable :: a -> IO Bool
  isSeekable a
_ = Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

  -- | seek to the specified position in the data.
  seek :: a -> SeekMode -> Integer -> IO Integer
  seek a
_ SeekMode
_ Integer
_ = IO Integer
forall a. IO a
ioe_unsupportedOperation

  -- | return the current position in the data.
  tell :: a -> IO Integer
  tell a
_ = IO Integer
forall a. IO a
ioe_unsupportedOperation

  -- | return the size of the data.
  getSize :: a -> IO Integer
  getSize a
_ = IO Integer
forall a. IO a
ioe_unsupportedOperation

  -- | change the size of the data.
  setSize :: a -> Integer -> IO ()
  setSize a
_ Integer
_ = IO ()
forall a. IO a
ioe_unsupportedOperation

  -- | for terminal devices, changes whether characters are echoed on
  -- the device.
  setEcho :: a -> Bool -> IO ()
  setEcho a
_ Bool
_ = IO ()
forall a. IO a
ioe_unsupportedOperation

  -- | returns the current echoing status.
  getEcho :: a -> IO Bool
  getEcho a
_ = IO Bool
forall a. IO a
ioe_unsupportedOperation

  -- | some devices (e.g. terminals) support a "raw" mode where
  -- characters entered are immediately made available to the program.
  -- If available, this operation enables raw mode.
  setRaw :: a -> Bool -> IO ()
  setRaw a
_ Bool
_ = IO ()
forall a. IO a
ioe_unsupportedOperation

  -- | returns the 'IODeviceType' corresponding to this device.
  devType :: a -> IO IODeviceType

  -- | duplicates the device, if possible.  The new device is expected
  -- to share a file pointer with the original device (like Unix @dup@).
  dup :: a -> IO a
  dup a
_ = IO a
forall a. IO a
ioe_unsupportedOperation

  -- | @dup2 source target@ replaces the target device with the source
  -- device.  The target device is closed first, if necessary, and then
  -- it is made into a duplicate of the first device (like Unix @dup2@).
  dup2 :: a -> a -> IO a
  dup2 a
_ a
_ = IO a
forall a. IO a
ioe_unsupportedOperation

ioe_unsupportedOperation :: IO a
ioe_unsupportedOperation :: forall a. IO a
ioe_unsupportedOperation = IOError -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO IOError
unsupportedOperation

-- | Type of a device that can be used to back a
-- 'GHC.IO.Handle.Handle' (see also 'GHC.Internal.IO.Handle.mkFileHandle'). The
-- standard libraries provide creation of 'GHC.IO.Handle.Handle's via
-- Posix file operations with file descriptors (see
-- 'GHC.Internal.IO.Handle.FD.mkHandleFromFD') with FD being the underlying
-- 'GHC.IO.Device.IODevice' instance.
--
-- Users may provide custom instances of 'GHC.IO.Device.IODevice'
-- which are expected to conform the following rules:

data IODeviceType
  = Directory -- ^ The standard libraries do not have direct support
              -- for this device type, but a user implementation is
              -- expected to provide a list of file names in
              -- the directory, in any order, separated by @\'\\0\'@
              -- characters, excluding the @"."@ and @".."@ names. See
              -- also 'System.Directory.getDirectoryContents'.  Seek
              -- operations are not supported on directories (other
              -- than to the zero position).
  | Stream    -- ^ A duplex communications channel (results in
              -- creation of a duplex 'GHC.IO.Handle.Handle'). The
              -- standard libraries use this device type when
              -- creating 'GHC.IO.Handle.Handle's for open sockets.
  | RegularFile -- ^ A file that may be read or written, and also
                -- may be seekable.
  | RawDevice -- ^ A "raw" (disk) device which supports block binary
              -- read and write operations and may be seekable only
              -- to positions of certain granularity (block-
              -- aligned).
  deriving ( IODeviceType -> IODeviceType -> Bool
(IODeviceType -> IODeviceType -> Bool)
-> (IODeviceType -> IODeviceType -> Bool) -> Eq IODeviceType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: IODeviceType -> IODeviceType -> Bool
== :: IODeviceType -> IODeviceType -> Bool
$c/= :: IODeviceType -> IODeviceType -> Bool
/= :: IODeviceType -> IODeviceType -> Bool
Eq -- ^ @since base-4.2.0.0
           )

-- -----------------------------------------------------------------------------
-- SeekMode type

-- | A mode that determines the effect of 'GHC.Internal.System.IO.hSeek' @hdl mode i@.
data SeekMode
  = AbsoluteSeek        -- ^ the position of @hdl@ is set to @i@.
  | RelativeSeek        -- ^ the position of @hdl@ is set to offset @i@
                        -- from the current position.
  | SeekFromEnd         -- ^ the position of @hdl@ is set to offset @i@
                        -- from the end of the file.
    deriving ( SeekMode -> SeekMode -> Bool
(SeekMode -> SeekMode -> Bool)
-> (SeekMode -> SeekMode -> Bool) -> Eq SeekMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SeekMode -> SeekMode -> Bool
== :: SeekMode -> SeekMode -> Bool
$c/= :: SeekMode -> SeekMode -> Bool
/= :: SeekMode -> SeekMode -> Bool
Eq   -- ^ @since base-4.2.0.0
             , Eq SeekMode
Eq SeekMode =>
(SeekMode -> SeekMode -> Ordering)
-> (SeekMode -> SeekMode -> Bool)
-> (SeekMode -> SeekMode -> Bool)
-> (SeekMode -> SeekMode -> Bool)
-> (SeekMode -> SeekMode -> Bool)
-> (SeekMode -> SeekMode -> SeekMode)
-> (SeekMode -> SeekMode -> SeekMode)
-> Ord SeekMode
SeekMode -> SeekMode -> Bool
SeekMode -> SeekMode -> Ordering
SeekMode -> SeekMode -> SeekMode
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: SeekMode -> SeekMode -> Ordering
compare :: SeekMode -> SeekMode -> Ordering
$c< :: SeekMode -> SeekMode -> Bool
< :: SeekMode -> SeekMode -> Bool
$c<= :: SeekMode -> SeekMode -> Bool
<= :: SeekMode -> SeekMode -> Bool
$c> :: SeekMode -> SeekMode -> Bool
> :: SeekMode -> SeekMode -> Bool
$c>= :: SeekMode -> SeekMode -> Bool
>= :: SeekMode -> SeekMode -> Bool
$cmax :: SeekMode -> SeekMode -> SeekMode
max :: SeekMode -> SeekMode -> SeekMode
$cmin :: SeekMode -> SeekMode -> SeekMode
min :: SeekMode -> SeekMode -> SeekMode
Ord  -- ^ @since base-4.2.0.0
             , Ord SeekMode
Ord SeekMode =>
((SeekMode, SeekMode) -> [SeekMode])
-> ((SeekMode, SeekMode) -> SeekMode -> Int)
-> ((SeekMode, SeekMode) -> SeekMode -> Int)
-> ((SeekMode, SeekMode) -> SeekMode -> Bool)
-> ((SeekMode, SeekMode) -> Int)
-> ((SeekMode, SeekMode) -> Int)
-> Ix SeekMode
(SeekMode, SeekMode) -> Int
(SeekMode, SeekMode) -> [SeekMode]
(SeekMode, SeekMode) -> SeekMode -> Bool
(SeekMode, SeekMode) -> SeekMode -> Int
forall a.
Ord a =>
((a, a) -> [a])
-> ((a, a) -> a -> Int)
-> ((a, a) -> a -> Int)
-> ((a, a) -> a -> Bool)
-> ((a, a) -> Int)
-> ((a, a) -> Int)
-> Ix a
$crange :: (SeekMode, SeekMode) -> [SeekMode]
range :: (SeekMode, SeekMode) -> [SeekMode]
$cindex :: (SeekMode, SeekMode) -> SeekMode -> Int
index :: (SeekMode, SeekMode) -> SeekMode -> Int
$cunsafeIndex :: (SeekMode, SeekMode) -> SeekMode -> Int
unsafeIndex :: (SeekMode, SeekMode) -> SeekMode -> Int
$cinRange :: (SeekMode, SeekMode) -> SeekMode -> Bool
inRange :: (SeekMode, SeekMode) -> SeekMode -> Bool
$crangeSize :: (SeekMode, SeekMode) -> Int
rangeSize :: (SeekMode, SeekMode) -> Int
$cunsafeRangeSize :: (SeekMode, SeekMode) -> Int
unsafeRangeSize :: (SeekMode, SeekMode) -> Int
Ix   -- ^ @since base-4.2.0.0
             , Int -> SeekMode
SeekMode -> Int
SeekMode -> [SeekMode]
SeekMode -> SeekMode
SeekMode -> SeekMode -> [SeekMode]
SeekMode -> SeekMode -> SeekMode -> [SeekMode]
(SeekMode -> SeekMode)
-> (SeekMode -> SeekMode)
-> (Int -> SeekMode)
-> (SeekMode -> Int)
-> (SeekMode -> [SeekMode])
-> (SeekMode -> SeekMode -> [SeekMode])
-> (SeekMode -> SeekMode -> [SeekMode])
-> (SeekMode -> SeekMode -> SeekMode -> [SeekMode])
-> Enum SeekMode
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: SeekMode -> SeekMode
succ :: SeekMode -> SeekMode
$cpred :: SeekMode -> SeekMode
pred :: SeekMode -> SeekMode
$ctoEnum :: Int -> SeekMode
toEnum :: Int -> SeekMode
$cfromEnum :: SeekMode -> Int
fromEnum :: SeekMode -> Int
$cenumFrom :: SeekMode -> [SeekMode]
enumFrom :: SeekMode -> [SeekMode]
$cenumFromThen :: SeekMode -> SeekMode -> [SeekMode]
enumFromThen :: SeekMode -> SeekMode -> [SeekMode]
$cenumFromTo :: SeekMode -> SeekMode -> [SeekMode]
enumFromTo :: SeekMode -> SeekMode -> [SeekMode]
$cenumFromThenTo :: SeekMode -> SeekMode -> SeekMode -> [SeekMode]
enumFromThenTo :: SeekMode -> SeekMode -> SeekMode -> [SeekMode]
Enum -- ^ @since base-4.2.0.0
             , ReadPrec [SeekMode]
ReadPrec SeekMode
Int -> ReadS SeekMode
ReadS [SeekMode]
(Int -> ReadS SeekMode)
-> ReadS [SeekMode]
-> ReadPrec SeekMode
-> ReadPrec [SeekMode]
-> Read SeekMode
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS SeekMode
readsPrec :: Int -> ReadS SeekMode
$creadList :: ReadS [SeekMode]
readList :: ReadS [SeekMode]
$creadPrec :: ReadPrec SeekMode
readPrec :: ReadPrec SeekMode
$creadListPrec :: ReadPrec [SeekMode]
readListPrec :: ReadPrec [SeekMode]
Read -- ^ @since base-4.2.0.0
             , Int -> SeekMode -> ShowS
[SeekMode] -> ShowS
SeekMode -> String
(Int -> SeekMode -> ShowS)
-> (SeekMode -> String) -> ([SeekMode] -> ShowS) -> Show SeekMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SeekMode -> ShowS
showsPrec :: Int -> SeekMode -> ShowS
$cshow :: SeekMode -> String
show :: SeekMode -> String
$cshowList :: [SeekMode] -> ShowS
showList :: [SeekMode] -> ShowS
Show -- ^ @since base-4.2.0.0
             )