{-# OPTIONS_GHC -Wno-redundant-constraints #-}

-- | Provides common file IO actions in terms of 'OsPath'.
--
-- @since 0.1
module FileSystem.IO
  ( -- * File handling
    readBinaryFileIO,
    writeBinaryFileIO,
    appendBinaryFileIO,
    openBinaryFileIO,
    withBinaryFileIO,

    -- * Errors
    throwPathIOError,
    throwFilePathIOError,
  )
where

import Control.Monad.Catch (MonadThrow, throwM)
import Data.ByteString (ByteString)
import FileSystem.OsPath qualified as FS.OsPath
import GHC.IO.Exception
  ( IOException
      ( IOError,
        ioe_description,
        ioe_errno,
        ioe_filename,
        ioe_handle,
        ioe_location,
        ioe_type
      ),
  )
import GHC.Stack.Types (HasCallStack)
import System.File.OsPath qualified as FileIO
import System.IO (Handle, IOMode)
import System.IO.Error (IOErrorType)
import System.OsPath (OsPath)

-- | @since 0.1
readBinaryFileIO :: OsPath -> IO ByteString
readBinaryFileIO :: OsPath -> IO ByteString
readBinaryFileIO = OsPath -> IO ByteString
FileIO.readFile'

-- | @since 0.1
writeBinaryFileIO :: OsPath -> ByteString -> IO ()
writeBinaryFileIO :: OsPath -> ByteString -> IO ()
writeBinaryFileIO = OsPath -> ByteString -> IO ()
FileIO.writeFile'

-- | @since 0.1
appendBinaryFileIO :: OsPath -> ByteString -> IO ()
appendBinaryFileIO :: OsPath -> ByteString -> IO ()
appendBinaryFileIO = OsPath -> ByteString -> IO ()
FileIO.appendFile'

-- | @since 0.1
openBinaryFileIO :: OsPath -> IOMode -> IO Handle
openBinaryFileIO :: OsPath -> IOMode -> IO Handle
openBinaryFileIO = OsPath -> IOMode -> IO Handle
FileIO.openBinaryFile

-- | @since 0.1
withBinaryFileIO :: OsPath -> IOMode -> (Handle -> IO a) -> IO a
withBinaryFileIO :: forall a. OsPath -> IOMode -> (Handle -> IO a) -> IO a
withBinaryFileIO = OsPath -> IOMode -> (Handle -> IO a) -> IO a
forall a. OsPath -> IOMode -> (Handle -> IO a) -> IO a
FileIO.withBinaryFile

-- | Helper for throwing 'IOException'.
--
-- @since 0.1
throwPathIOError ::
  (HasCallStack, MonadThrow m) =>
  -- | Path upon which the IO operation failed.
  OsPath ->
  -- | String location (e.g. function name).
  String ->
  -- | Type of exception.
  IOErrorType ->
  -- | Description.
  String ->
  m a
throwPathIOError :: forall (m :: * -> *) a.
(HasCallStack, MonadThrow m) =>
OsPath -> String -> IOErrorType -> String -> m a
throwPathIOError = String -> String -> IOErrorType -> String -> m a
forall (m :: * -> *) a.
(HasCallStack, MonadThrow m) =>
String -> String -> IOErrorType -> String -> m a
throwFilePathIOError (String -> String -> IOErrorType -> String -> m a)
-> (OsPath -> String)
-> OsPath
-> String
-> IOErrorType
-> String
-> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsPath -> String
FS.OsPath.decodeLenient
{-# INLINEABLE throwPathIOError #-}

-- | Helper for throwing 'IOException' with legacy FilePath.
--
-- @since 0.1
throwFilePathIOError ::
  (HasCallStack, MonadThrow m) =>
  -- | Path upon which the IO operation failed.
  FilePath ->
  -- | String location (e.g. function name).
  String ->
  -- | Type of exception.
  IOErrorType ->
  -- | Description.
  String ->
  m a
throwFilePathIOError :: forall (m :: * -> *) a.
(HasCallStack, MonadThrow m) =>
String -> String -> IOErrorType -> String -> m a
throwFilePathIOError String
path String
loc IOErrorType
ty String
desc =
  IOException -> m a
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOException -> m a) -> IOException -> m a
forall a b. (a -> b) -> a -> b
$
    IOError
      { ioe_handle :: Maybe Handle
ioe_handle = Maybe Handle
forall a. Maybe a
Nothing,
        ioe_type :: IOErrorType
ioe_type = IOErrorType
ty,
        ioe_location :: String
ioe_location = String
loc,
        ioe_description :: String
ioe_description = String
desc,
        ioe_errno :: Maybe CInt
ioe_errno = Maybe CInt
forall a. Maybe a
Nothing,
        ioe_filename :: Maybe String
ioe_filename = String -> Maybe String
forall a. a -> Maybe a
Just String
path
      }
{-# INLINEABLE throwFilePathIOError #-}