content: {-# LANGUAGE CPP               #-}
  {-# LANGUAGE FlexibleInstances #-}
  
  #if __GLASGOW_HASKELL__ >= 702
  {-# LANGUAGE Trustworthy       #-}
  #endif
  
  -- | Input and output streams for file 'Handle's.
  module System.IO.Streams.Handle
   ( -- * Handle conversions
     handleToInputStream
   , handleToOutputStream
   , handleToStreams
   , inputStreamToHandle
   , outputStreamToHandle
   , streamPairToHandle
  
     -- * Standard system handles
   , stdin
   , stdout
   , stderr
   ) where
  
  ------------------------------------------------------------------------------
  import           Data.ByteString            (ByteString)
  import qualified Data.ByteString            as S
  import qualified GHC.IO.Handle              as H
  import           System.IO                  (Handle, hFlush)
  import qualified System.IO                  as IO
  import           System.IO.Unsafe           (unsafePerformIO)
  ------------------------------------------------------------------------------
  import           System.IO.Streams.Internal (InputStream, OutputStream, SP (..), lockingInputStream, lockingOutputStream, makeInputStream, makeOutputStream)
  
  
  ------------------------------------------------------------------------------
  bUFSIZ :: Int
  bUFSIZ = 32752
  
  
  ------------------------------------------------------------------------------
  -- | Converts a read-only handle into an 'InputStream' of strict 'ByteString's.
  --
  -- Note that the wrapped handle is /not/ closed when it yields end-of-stream;
  -- you can use 'System.IO.Streams.Combinators.atEndOfInput' to close the handle
  -- if you would like this behaviour.
  handleToInputStream :: Handle -> IO (InputStream ByteString)
  handleToInputStream h = makeInputStream f
    where
      f = do
          x <- S.hGetSome h bUFSIZ
          return $! if S.null x then Nothing else Just x
  
  
  ------------------------------------------------------------------------------
  -- | Converts a writable handle into an 'OutputStream' of strict 'ByteString's.
  --
  -- Note that the wrapped handle is /not/ closed when it receives end-of-stream;
  -- you can use 'System.IO.Streams.Combinators.atEndOfOutput' to close the
  -- handle if you would like this behaviour.
  --
  -- /Note/: to force the 'Handle' to be flushed, you can write a null string to
  -- the returned 'OutputStream':
  --
  -- > Streams.write (Just "") os
  handleToOutputStream :: Handle -> IO (OutputStream ByteString)
  handleToOutputStream h = makeOutputStream f
    where
      f Nothing  = hFlush h
      f (Just x) = if S.null x
                     then hFlush h
                     else S.hPut h x
  
  
  ------------------------------------------------------------------------------
  -- | Converts a readable and writable handle into an 'InputStream'/'OutputStream'
  -- of strict 'ByteString's.
  --
  -- Note that the wrapped handle is /not/ closed when it receives
  -- end-of-stream; you can use
  -- 'System.IO.Streams.Combinators.atEndOfOutput' to close the handle
  -- if you would like this behaviour.
  --
  -- /Note/: to force the 'Handle' to be flushed, you can write a null string to
  -- the returned 'OutputStream':
  --
  -- > Streams.write (Just "") os
  --
  -- /Since: 1.3.4.0./
  handleToStreams :: Handle
                  -> IO (InputStream ByteString, OutputStream ByteString)
  handleToStreams h = do
      is <- handleToInputStream h
      os <- handleToOutputStream h
      return $! (is, os)
  
  
  ------------------------------------------------------------------------------
  -- | Converts an 'InputStream' over bytestrings to a read-only 'Handle'. Note
  -- that the generated handle is opened unbuffered in binary mode (i.e. no
  -- newline translation is performed).
  --
  -- Note: the 'InputStream' passed into this function is wrapped in
  -- 'lockingInputStream' to make it thread-safe.
  --
  -- /Since: 1.0.2.0./
  inputStreamToHandle :: InputStream ByteString -> IO Handle
  inputStreamToHandle is0 = do
      is <- lockingInputStream is0
      h <- H.mkDuplexHandle is "*input-stream*" Nothing $! H.noNewlineTranslation
      H.hSetBuffering h H.NoBuffering
      return h
  
  
  ------------------------------------------------------------------------------
  -- | Converts an 'OutputStream' over bytestrings to a write-only 'Handle'. Note
  -- that the 'Handle' will be opened in non-buffering mode; if you buffer the
  -- 'OutputStream' using the 'Handle' buffering then @io-streams@ will copy the
  -- 'Handle' buffer when sending 'ByteString' values to the output, which might
  -- not be what you want.
  --
  -- When the output buffer, if used, is flushed (using 'System.IO.hFlush'), an
  -- empty string is written to the provided 'OutputStream'.
  --
  -- /Note/: the 'OutputStream' passed into this function is wrapped in
  -- 'lockingOutputStream' to make it thread-safe.
  --
  -- /Since: 1.0.2.0./
  outputStreamToHandle :: OutputStream ByteString -> IO Handle
  outputStreamToHandle os0 = do
      os <- lockingOutputStream os0
      h <- H.mkDuplexHandle os "*output-stream*" Nothing $! H.noNewlineTranslation
      H.hSetBuffering h H.NoBuffering
      return $! h
  
  
  ------------------------------------------------------------------------------
  -- | Converts a pair of 'InputStream' and 'OutputStream' over bytestrings to a
  -- read-write 'Handle'.
  --
  -- Note: the streams passed into this function are wrapped in
  -- locking primitives to make them thread-safe.
  --
  -- /Since: 1.0.2.0./
  streamPairToHandle :: InputStream ByteString -> OutputStream ByteString -> IO Handle
  streamPairToHandle is0 os0 = do
      is <- lockingInputStream is0
      os <- lockingOutputStream os0
      h <- H.mkDuplexHandle (SP is os) "*stream*" Nothing $! H.noNewlineTranslation
      H.hSetBuffering h H.NoBuffering
      return $! h
  
  
  ------------------------------------------------------------------------------
  -- | An 'InputStream' for 'IO.stdin'.
  stdin :: InputStream ByteString
  stdin = unsafePerformIO (handleToInputStream IO.stdin >>= lockingInputStream)
  {-# NOINLINE stdin #-}
  
  
  ------------------------------------------------------------------------------
  -- | An 'OutputStream' for 'IO.stdout'.
  stdout :: OutputStream ByteString
  stdout = unsafePerformIO (handleToOutputStream IO.stdout >>=
                            lockingOutputStream)
  {-# NOINLINE stdout #-}
  
  
  ------------------------------------------------------------------------------
  -- | An 'OutputStream' for 'IO.stderr'.
  stderr :: OutputStream ByteString
  stderr = unsafePerformIO (handleToOutputStream IO.stderr >>=
                            lockingOutputStream)
  {-# NOINLINE stderr #-}
  