{-# LANGUAGE DeriveDataTypeable, ForeignFunctionInterface #-} module Data.Text.ICU.Error.Internal ( -- * Types ErrorCode(..) -- ** Low-level types , UErrorCode -- * Functions , isFailure , isSuccess , errorName , handleError , throwOnError , withError ) where import Control.Exception import Foreign.Ptr import Foreign.Marshal.Alloc import Data.Typeable (Typeable) import Foreign.C.String (CString, peekCString) import Foreign.C.Types (CInt) import Foreign.Storable import System.IO.Unsafe (unsafePerformIO) type UErrorCode = CInt -- | ICU error code. newtype ErrorCode = ErrorCode { fromErrorCode :: UErrorCode } deriving (Eq, Typeable) instance Show ErrorCode where show code = "ErrorCode " ++ errorName code instance Exception ErrorCode -- | Indicate whether the given error code is a success. isSuccess :: ErrorCode -> Bool {-# INLINE isSuccess #-} isSuccess = (<= 0) . fromErrorCode -- | Indicate whether the given error code is a failure. isFailure :: ErrorCode -> Bool {-# INLINE isFailure #-} isFailure = (> 0) . fromErrorCode -- | Throw an exception if the given code is actually an error. throwOnError :: UErrorCode -> IO () {-# INLINE throwOnError #-} throwOnError code = do let err = (ErrorCode code) if isFailure err then throw err else return () withError :: (Ptr UErrorCode -> IO a) -> IO (ErrorCode, a) {-# INLINE withError #-} withError action = alloca $ \errPtr -> do poke errPtr 0 ret <- action errPtr err <- peek errPtr return (ErrorCode err, ret) handleError :: (Ptr UErrorCode -> IO a) -> IO a {-# INLINE handleError #-} handleError action = alloca $ \errPtr -> do poke errPtr 0 ret <- action errPtr throwOnError =<< peek errPtr return ret -- | Return a string representing the name of the given error code. errorName :: ErrorCode -> String errorName code = unsafePerformIO $ peekCString (u_errorName (fromErrorCode code)) foreign import ccall unsafe "unicode/utypes.h u_errorName_4_0" u_errorName :: UErrorCode -> CString