{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Std.IO.Exception
(
SomeIOException(..)
, ioExceptionToException
, ioExceptionFromException
, IOEInfo(..)
, AlreadyExists(..)
, NoSuchThing(..)
, ResourceBusy(..)
, ResourceExhausted(..)
, EOF(..)
, IllegalOperation(..)
, PermissionDenied(..)
, UnsatisfiedConstraints(..)
, SystemError(..)
, ProtocolError(..)
, OtherError(..)
, InvalidArgument(..)
, InappropriateType(..)
, HardwareFault(..)
, UnsupportedOperation(..)
, TimeExpired(..)
, ResourceVanished(..)
, Interrupted(..)
, throwOOMIfNull
, throwUVIfMinus
, throwUVIfMinus_
, throwECLOSED
, throwECLOSEDSTM
, throwUVError
, module Control.Exception
, HasCallStack
, callStack
) where
import Control.Exception hiding (IOException)
import Control.Monad
import Control.Concurrent.STM
import Data.Typeable
import Foreign.Ptr
import Foreign.C.Types
import GHC.Stack
import Std.IO.UV.Errno
data SomeIOException = forall e . Exception e => SomeIOException e
deriving Typeable
instance Show SomeIOException where
show (SomeIOException e) = show e
instance Exception SomeIOException
ioExceptionToException :: Exception e => e -> SomeException
ioExceptionToException = toException . SomeIOException
ioExceptionFromException :: Exception e => SomeException -> Maybe e
ioExceptionFromException x = do
SomeIOException a <- fromException x
cast a
#define IOE(e) data e = e IOEInfo deriving (Show, Typeable); \
instance Exception e where \
{ toException = ioExceptionToException \
; fromException = ioExceptionFromException \
}
IOE(AlreadyExists)
IOE(NoSuchThing)
IOE(ResourceBusy)
IOE(ResourceExhausted)
IOE(EOF)
IOE(IllegalOperation)
IOE(PermissionDenied)
IOE(UnsatisfiedConstraints)
IOE(SystemError)
IOE(ProtocolError)
IOE(OtherError)
IOE(InvalidArgument)
IOE(InappropriateType)
IOE(HardwareFault)
IOE(UnsupportedOperation)
IOE(TimeExpired)
IOE(ResourceVanished)
IOE(Interrupted)
throwOOMIfNull :: HasCallStack
=> IO (Ptr a)
-> IO (Ptr a)
throwOOMIfNull f = do
addr <- f
if addr == nullPtr
then throwIO (ResourceExhausted (IOEInfo "OOM" "out of memory when doing allocation" callStack))
else return addr
throwUVIfMinus :: (HasCallStack, Integral a)
=> IO a
-> IO a
throwUVIfMinus f = do
errno <- f
let errno' = fromIntegral errno
if errno' < 0
then do
name <- uvErrName errno'
desc <- uvStdError errno'
throwUVError errno' (IOEInfo name desc callStack)
else return errno
throwUVIfMinus_ :: (HasCallStack, Integral a)
=> IO a
-> IO ()
throwUVIfMinus_ f = do
errno <- f
let errno' = fromIntegral errno
when (errno' < 0) $ do
name <- uvErrName errno'
desc <- uvStdError errno'
throwUVError errno' (IOEInfo name desc callStack)
throwECLOSED :: HasCallStack => IO a
throwECLOSED = throwIO (ResourceVanished
(IOEInfo "ECLOSED" "resource is closed" callStack))
throwECLOSEDSTM :: HasCallStack => STM a
throwECLOSEDSTM = throwSTM (ResourceVanished
(IOEInfo "ECLOSED" "resource is closed" callStack))
data IOEInfo = IOEInfo
{ ioeName :: String
, ioeDescription :: String
, ioeCallStack :: CallStack
}
instance Show IOEInfo where
show (IOEInfo errno desc cstack) =
"{name:" ++ errno ++
", description:" ++ desc ++
", callstack:" ++ prettyCallStack cstack ++ "}"
throwUVError :: CInt -> IOEInfo -> IO a
throwUVError e info = case e of
UV_EOF -> throwIO (EOF info)
UV_E2BIG -> throwIO (ResourceExhausted info)
UV_EACCES -> throwIO (PermissionDenied info)
UV_EADDRINUSE -> throwIO (ResourceBusy info)
UV_EADDRNOTAVAIL -> throwIO (UnsupportedOperation info)
UV_EAFNOSUPPORT -> throwIO (UnsupportedOperation info)
UV_EAGAIN -> throwIO (ResourceExhausted info)
UV_EAI_ADDRFAMILY -> throwIO (UnsupportedOperation info)
UV_EAI_AGAIN -> throwIO (ResourceExhausted info)
UV_EAI_BADFLAGS -> throwIO (UnsupportedOperation info)
UV_EAI_BADHINTS -> throwIO (UnsupportedOperation info)
UV_EAI_CANCELED -> throwIO (ResourceVanished info)
UV_EAI_FAIL -> throwIO (OtherError info)
UV_EAI_FAMILY -> throwIO (UnsupportedOperation info)
UV_EAI_MEMORY -> throwIO (ResourceExhausted info)
UV_EAI_NODATA -> throwIO (NoSuchThing info)
UV_EAI_NONAME -> throwIO (NoSuchThing info)
UV_EAI_OVERFLOW -> throwIO (InvalidArgument info)
UV_EAI_PROTOCOL -> throwIO (ProtocolError info)
UV_EAI_SERVICE -> throwIO (UnsupportedOperation info)
UV_EAI_SOCKTYPE -> throwIO (UnsupportedOperation info)
UV_EALREADY -> throwIO (AlreadyExists info)
UV_EBADF -> throwIO (InvalidArgument info)
UV_EBUSY -> throwIO (ResourceBusy info)
UV_ECANCELED -> throwIO (ResourceVanished info)
UV_ECHARSET -> throwIO (OtherError info)
UV_ECONNABORTED -> throwIO (ResourceVanished info)
UV_ECONNREFUSED -> throwIO (NoSuchThing info)
UV_ECONNRESET -> throwIO (ResourceVanished info)
UV_EDESTADDRREQ -> throwIO (InvalidArgument info)
UV_EEXIST -> throwIO (AlreadyExists info)
UV_EFAULT -> throwIO (OtherError info)
UV_EFBIG -> throwIO (PermissionDenied info)
UV_EHOSTUNREACH -> throwIO (NoSuchThing info)
UV_EINTR -> throwIO (Interrupted info)
UV_EINVAL -> throwIO (InvalidArgument info)
UV_EIO -> throwIO (HardwareFault info)
UV_EISCONN -> throwIO (AlreadyExists info)
UV_EISDIR -> throwIO (InappropriateType info)
UV_ELOOP -> throwIO (InvalidArgument info)
UV_EMFILE -> throwIO (ResourceExhausted info)
UV_EMSGSIZE -> throwIO (ResourceExhausted info)
UV_ENAMETOOLONG -> throwIO (InvalidArgument info)
UV_ENETDOWN -> throwIO (ResourceVanished info)
UV_ENETUNREACH -> throwIO (NoSuchThing info)
UV_ENFILE -> throwIO (ResourceExhausted info)
UV_ENOBUFS -> throwIO (ResourceExhausted info)
UV_ENODEV -> throwIO (UnsupportedOperation info)
UV_ENOENT -> throwIO (NoSuchThing info)
UV_ENOMEM -> throwIO (ResourceExhausted info)
UV_ENOPROTOOPT -> throwIO (UnsupportedOperation info)
UV_ENOSPC -> throwIO (ResourceExhausted info)
UV_ENOSYS -> throwIO (UnsupportedOperation info)
UV_ENOTCONN -> throwIO (InvalidArgument info)
UV_ENOTDIR -> throwIO (InappropriateType info)
UV_ENOTEMPTY -> throwIO (UnsatisfiedConstraints info)
UV_ENOTSOCK -> throwIO (InvalidArgument info)
UV_ENOTSUP -> throwIO (UnsupportedOperation info)
UV_EPERM -> throwIO (PermissionDenied info)
UV_EPIPE -> throwIO (ResourceVanished info)
UV_EPROTO -> throwIO (ProtocolError info)
UV_EPROTONOSUPPORT -> throwIO (ProtocolError info)
UV_EPROTOTYPE -> throwIO (ProtocolError info)
UV_ERANGE -> throwIO (UnsupportedOperation info)
UV_EROFS -> throwIO (PermissionDenied info)
UV_ESHUTDOWN -> throwIO (IllegalOperation info)
UV_ESPIPE -> throwIO (UnsupportedOperation info)
UV_ESRCH -> throwIO (NoSuchThing info)
UV_ETIMEDOUT -> throwIO (TimeExpired info)
UV_ETXTBSY -> throwIO (ResourceBusy info)
UV_EXDEV -> throwIO (UnsupportedOperation info)
UV_UNKNOWN -> throwIO (OtherError info)
UV_ENXIO -> throwIO (NoSuchThing info)
UV_EMLINK -> throwIO (ResourceExhausted info)
_ -> throwIO (OtherError info)