{-# LANGUAGE LambdaCase #-}
module System.FS.IO.Handle (
HandleOS (..)
, closeHandleOS
, isHandleClosedException
, isOpenHandleOS
, withOpenHandle
) where
import Control.Concurrent.MVar
import Control.Exception hiding (handle)
import Data.Maybe (isJust)
import System.IO.Error as IO
data HandleOS osHandle = HandleOS {
forall osHandle. HandleOS osHandle -> FilePath
filePath :: FilePath
, forall osHandle. HandleOS osHandle -> MVar (Maybe osHandle)
handle :: MVar (Maybe osHandle)
}
instance Eq (HandleOS a) where
HandleOS a
h1 == :: HandleOS a -> HandleOS a -> Bool
== HandleOS a
h2 = HandleOS a -> MVar (Maybe a)
forall osHandle. HandleOS osHandle -> MVar (Maybe osHandle)
handle HandleOS a
h1 MVar (Maybe a) -> MVar (Maybe a) -> Bool
forall a. Eq a => a -> a -> Bool
== HandleOS a -> MVar (Maybe a)
forall osHandle. HandleOS osHandle -> MVar (Maybe osHandle)
handle HandleOS a
h2
instance Show (HandleOS a) where
show :: HandleOS a -> FilePath
show HandleOS a
h = FilePath
"<Handle " FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ HandleOS a -> FilePath
forall osHandle. HandleOS osHandle -> FilePath
filePath HandleOS a
h FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
">"
isOpenHandleOS :: HandleOS osHandle -> IO Bool
isOpenHandleOS :: forall osHandle. HandleOS osHandle -> IO Bool
isOpenHandleOS = (Maybe osHandle -> Bool) -> IO (Maybe osHandle) -> IO Bool
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe osHandle -> Bool
forall a. Maybe a -> Bool
isJust (IO (Maybe osHandle) -> IO Bool)
-> (HandleOS osHandle -> IO (Maybe osHandle))
-> HandleOS osHandle
-> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MVar (Maybe osHandle) -> IO (Maybe osHandle)
forall a. MVar a -> IO a
readMVar (MVar (Maybe osHandle) -> IO (Maybe osHandle))
-> (HandleOS osHandle -> MVar (Maybe osHandle))
-> HandleOS osHandle
-> IO (Maybe osHandle)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HandleOS osHandle -> MVar (Maybe osHandle)
forall osHandle. HandleOS osHandle -> MVar (Maybe osHandle)
handle
closeHandleOS :: HandleOS osHandle -> (osHandle -> IO ()) -> IO ()
closeHandleOS :: forall osHandle. HandleOS osHandle -> (osHandle -> IO ()) -> IO ()
closeHandleOS (HandleOS FilePath
_ MVar (Maybe osHandle)
hVar) osHandle -> IO ()
close =
MVar (Maybe osHandle)
-> (Maybe osHandle -> IO (Maybe osHandle, ())) -> IO ()
forall a b. MVar a -> (a -> IO (a, b)) -> IO b
modifyMVar MVar (Maybe osHandle)
hVar ((Maybe osHandle -> IO (Maybe osHandle, ())) -> IO ())
-> (Maybe osHandle -> IO (Maybe osHandle, ())) -> IO ()
forall a b. (a -> b) -> a -> b
$ \case
Maybe osHandle
Nothing -> (Maybe osHandle, ()) -> IO (Maybe osHandle, ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe osHandle
forall a. Maybe a
Nothing, ())
Just osHandle
h -> osHandle -> IO ()
close osHandle
h IO () -> IO (Maybe osHandle, ()) -> IO (Maybe osHandle, ())
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Maybe osHandle, ()) -> IO (Maybe osHandle, ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe osHandle
forall a. Maybe a
Nothing, ())
withOpenHandle :: String -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle :: forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
label (HandleOS FilePath
fp MVar (Maybe osHandle)
hVar) osHandle -> IO a
k =
MVar (Maybe osHandle) -> (Maybe osHandle -> IO a) -> IO a
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar (Maybe osHandle)
hVar ((Maybe osHandle -> IO a) -> IO a)
-> (Maybe osHandle -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \case
Maybe osHandle
Nothing -> IOException -> IO a
forall e a. Exception e => e -> IO a
throwIO (FilePath -> FilePath -> IOException
handleClosedException FilePath
fp FilePath
label)
Just osHandle
fd -> osHandle -> IO a
k osHandle
fd
handleClosedException :: FilePath -> String -> IOException
handleClosedException :: FilePath -> FilePath -> IOException
handleClosedException FilePath
fp FilePath
label =
(IOException -> IOErrorType -> IOException)
-> IOErrorType -> IOException -> IOException
forall a b c. (a -> b -> c) -> b -> a -> c
flip IOException -> IOErrorType -> IOException
IO.ioeSetErrorType IOErrorType
IO.illegalOperationErrorType
(IOException -> IOException) -> IOException -> IOException
forall a b. (a -> b) -> a -> b
$ (IOException -> FilePath -> IOException)
-> FilePath -> IOException -> IOException
forall a b c. (a -> b -> c) -> b -> a -> c
flip IOException -> FilePath -> IOException
IO.ioeSetFileName FilePath
fp
(IOException -> IOException) -> IOException -> IOException
forall a b. (a -> b) -> a -> b
$ FilePath -> IOException
userError (FilePath
label FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
": FHandle closed")
isHandleClosedException :: IOException -> Bool
isHandleClosedException :: IOException -> Bool
isHandleClosedException IOException
ioErr =
IOErrorType -> Bool
IO.isUserErrorType (IOException -> IOErrorType
IO.ioeGetErrorType IOException
ioErr)