    {-# LANGUAGE Trustworthy #-}
    {-# LANGUAGE NoImplicitPrelude #-}
    {-# OPTIONS_GHC -funbox-strict-fields #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  GHC.IO.BufferedIO
    -- Copyright   :  (c) The University of Glasgow 2008
    -- License     :  see libraries/base/LICENSE
    --
    -- Maintainer  :  cvs-ghc@haskell.org
    -- Stability   :  internal
    -- Portability :  non-portable (GHC Extensions)
    --
    -- Class of buffered IO devices
    --
    -----------------------------------------------------------------------------

    module GHC.IO.BufferedIO (
            BufferedIO(..),
            readBuf, readBufNonBlocking, writeBuf, writeBufNonBlocking
        ) where

    import GHC.Base
    import GHC.Ptr
    import Data.Word
    import GHC.Num
    import GHC.IO.Device as IODevice
    import GHC.IO.Device as RawIO
    import GHC.IO.Buffer

    -- | The purpose of 'BufferedIO' is to provide a common interface for I/O
    -- devices that can read and write data through a buffer.  Devices that
    -- implement 'BufferedIO' include ordinary files, memory-mapped files,
    -- and bytestrings.  The underlying device implementing a 'System.IO.Handle'
    -- must provide 'BufferedIO'.
    --
    class BufferedIO dev where
      -- | allocate a new buffer.  The size of the buffer is at the
      -- discretion of the device; e.g. for a memory-mapped file the
      -- buffer will probably cover the entire file.
      newBuffer         :: dev -> BufferState -> IO (Buffer Word8)

      -- | reads bytes into the buffer, blocking if there are no bytes
      -- available.  Returns the number of bytes read (zero indicates
      -- end-of-file), and the new buffer.
      fillReadBuffer    :: dev -> Buffer Word8 -> IO (Int, Buffer Word8)

      -- | reads bytes into the buffer without blocking.  Returns the
      -- number of bytes read (Nothing indicates end-of-file), and the new
      -- buffer.
      fillReadBuffer0   :: dev -> Buffer Word8 -> IO (Maybe Int, Buffer Word8)

      -- | Prepares an empty write buffer.  This lets the device decide
      -- how to set up a write buffer: the buffer may need to point to a
      -- specific location in memory, for example.  This is typically used
      -- by the client when switching from reading to writing on a
      -- buffered read/write device.
      --
      -- There is no corresponding operation for read buffers, because before
      -- reading the client will always call 'fillReadBuffer'.
      emptyWriteBuffer  :: dev -> Buffer Word8 -> IO (Buffer Word8)
      emptyWriteBuffer dev
    _dev Buffer Word8
    buf
        = Buffer Word8 -> IO (Buffer Word8)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Buffer Word8
    buf{ bufL=0, bufR=0, bufState = WriteBuffer }

      -- | Flush all the data from the supplied write buffer out to the device.
      -- The returned buffer should be empty, and ready for writing.
      flushWriteBuffer  :: dev -> Buffer Word8 -> IO (Buffer Word8)

      -- | Flush data from the supplied write buffer out to the device
      -- without blocking.  Returns the number of bytes written and the
      -- remaining buffer.
      flushWriteBuffer0 :: dev -> Buffer Word8 -> IO (Int, Buffer Word8)

    -- for an I/O device, these operations will perform reading/writing
    -- to/from the device.

    -- for a memory-mapped file, the buffer will be the whole file in
    -- memory.  fillReadBuffer sets the pointers to encompass the whole
    -- file, and flushWriteBuffer needs to do no I/O.  A memory-mapped
    -- file has to maintain its own file pointer.

    -- for a bytestring, again the buffer should match the bytestring in
    -- memory.

    -- ---------------------------------------------------------------------------
    -- Low-level read/write to/from buffers

    -- These operations make it easy to implement an instance of 'BufferedIO'
    -- for an object that supports 'RawIO'.

    readBuf :: RawIO dev => dev -> Buffer Word8 -> IO (Int, Buffer Word8)
    readBuf :: forall dev.
    RawIO dev =>
    dev -> Buffer Word8 -> IO (Int, Buffer Word8)
    readBuf dev
    dev Buffer Word8
    bbuf = do
      let bytes :: Int
    bytes = Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufferAvailable Buffer Word8
    bbuf
      let offset :: Word64
    offset = Buffer Word8 -> Word64
    forall e. Buffer e -> Word64
    bufferOffset Buffer Word8
    bbuf
      Int
    res <- Buffer Word8 -> (Ptr Word8 -> IO Int) -> IO Int
    forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
    withBuffer Buffer Word8
    bbuf ((Ptr Word8 -> IO Int) -> IO Int)
    -> (Ptr Word8 -> IO Int) -> IO Int
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    ptr ->
                 dev -> Ptr Word8 -> Word64 -> Int -> IO Int
    forall a. RawIO a => a -> Ptr Word8 -> Word64 -> Int -> IO Int
    RawIO.read dev
    dev (Ptr Word8
    ptr Ptr Word8 -> Int -> Ptr Word8
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufR Buffer Word8
    bbuf) Word64
    offset Int
    bytes
      let bbuf' :: Buffer Word8
    bbuf' = Int -> Buffer Word8 -> Buffer Word8
    forall e. Int -> Buffer e -> Buffer e
    bufferAddOffset Int
    res Buffer Word8
    bbuf
      (Int, Buffer Word8) -> IO (Int, Buffer Word8)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int
    res, Buffer Word8
    bbuf'{ bufR = bufR bbuf' + res })
             -- zero indicates end of file

    readBufNonBlocking :: RawIO dev => dev -> Buffer Word8
                         -> IO (Maybe Int,   -- Nothing ==> end of file
                                             -- Just n  ==> n bytes were read (n>=0)
                                Buffer Word8)
    readBufNonBlocking :: forall dev.
    RawIO dev =>
    dev -> Buffer Word8 -> IO (Maybe Int, Buffer Word8)
    readBufNonBlocking dev
    dev Buffer Word8
    bbuf = do
      let bytes :: Int
    bytes = Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufferAvailable Buffer Word8
    bbuf
      let offset :: Word64
    offset = Buffer Word8 -> Word64
    forall e. Buffer e -> Word64
    bufferOffset Buffer Word8
    bbuf
      Maybe Int
    res <- Buffer Word8 -> (Ptr Word8 -> IO (Maybe Int)) -> IO (Maybe Int)
    forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
    withBuffer Buffer Word8
    bbuf ((Ptr Word8 -> IO (Maybe Int)) -> IO (Maybe Int))
    -> (Ptr Word8 -> IO (Maybe Int)) -> IO (Maybe Int)
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    ptr ->
               dev -> Ptr Word8 -> Word64 -> Int -> IO (Maybe Int)
    forall a.
    RawIO a =>
    a -> Ptr Word8 -> Word64 -> Int -> IO (Maybe Int)
    IODevice.readNonBlocking dev
    dev (Ptr Word8
    ptr Ptr Word8 -> Int -> Ptr Word8
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufR Buffer Word8
    bbuf) Word64
    offset Int
    bytes
      case Maybe Int
    res of
         Maybe Int
    Nothing -> (Maybe Int, Buffer Word8) -> IO (Maybe Int, Buffer Word8)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe Int
    forall a. Maybe a
    Nothing, Buffer Word8
    bbuf)
         Just Int
    n  -> do let bbuf' :: Buffer Word8
    bbuf' = Int -> Buffer Word8 -> Buffer Word8
    forall e. Int -> Buffer e -> Buffer e
    bufferAddOffset Int
    n Buffer Word8
    bbuf
                       (Maybe Int, Buffer Word8) -> IO (Maybe Int, Buffer Word8)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> Maybe Int
    forall a. a -> Maybe a
    Just Int
    n, Buffer Word8
    bbuf'{ bufR = bufR bbuf' + n })

    writeBuf :: RawIO dev => dev -> Buffer Word8 -> IO (Buffer Word8)
    writeBuf :: forall dev. RawIO dev => dev -> Buffer Word8 -> IO (Buffer Word8)
    writeBuf dev
    dev Buffer Word8
    bbuf = do
      let bytes :: Int
    bytes = Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufferElems Buffer Word8
    bbuf
      let offset :: Word64
    offset = Buffer Word8 -> Word64
    forall e. Buffer e -> Word64
    bufferOffset Buffer Word8
    bbuf
      Buffer Word8 -> (Ptr Word8 -> IO ()) -> IO ()
    forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
    withBuffer Buffer Word8
    bbuf ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    ptr ->
          dev -> Ptr Word8 -> Word64 -> Int -> IO ()
    forall a. RawIO a => a -> Ptr Word8 -> Word64 -> Int -> IO ()
    IODevice.write dev
    dev (Ptr Word8
    ptr Ptr Word8 -> Int -> Ptr Word8
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufL Buffer Word8
    bbuf) Word64
    offset Int
    bytes
      let bbuf' :: Buffer Word8
    bbuf' = Int -> Buffer Word8 -> Buffer Word8
    forall e. Int -> Buffer e -> Buffer e
    bufferAddOffset Int
    bytes Buffer Word8
    bbuf
      Buffer Word8 -> IO (Buffer Word8)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Buffer Word8
    bbuf'{ bufL=0, bufR=0 }

    -- XXX ToDo
    writeBufNonBlocking :: RawIO dev => dev -> Buffer Word8 -> IO (Int, Buffer Word8)
    writeBufNonBlocking :: forall dev.
    RawIO dev =>
    dev -> Buffer Word8 -> IO (Int, Buffer Word8)
    writeBufNonBlocking dev
    dev Buffer Word8
    bbuf = do
      let bytes :: Int
    bytes = Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufferElems Buffer Word8
    bbuf
      let offset :: Word64
    offset = Buffer Word8 -> Word64
    forall e. Buffer e -> Word64
    bufferOffset Buffer Word8
    bbuf
      Int
    res <- Buffer Word8 -> (Ptr Word8 -> IO Int) -> IO Int
    forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
    withBuffer Buffer Word8
    bbuf ((Ptr Word8 -> IO Int) -> IO Int)
    -> (Ptr Word8 -> IO Int) -> IO Int
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    ptr ->
                dev -> Ptr Word8 -> Word64 -> Int -> IO Int
    forall a. RawIO a => a -> Ptr Word8 -> Word64 -> Int -> IO Int
    IODevice.writeNonBlocking dev
    dev (Ptr Word8
    ptr Ptr Word8 -> Int -> Ptr Word8
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufL Buffer Word8
    bbuf) Word64
    offset Int
    bytes
      let bbuf' :: Buffer Word8
    bbuf' = Int -> Buffer Word8 -> Buffer Word8
    forall e. Int -> Buffer e -> Buffer e
    bufferAddOffset Int
    bytes Buffer Word8
    bbuf
      (Int, Buffer Word8) -> IO (Int, Buffer Word8)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int
    res, Int -> Buffer Word8 -> Buffer Word8
    forall e. Int -> Buffer e -> Buffer e
    bufferAdjustL (Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufL Buffer Word8
    bbuf Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    res) Buffer Word8
    bbuf')