mempack-0.2.0.0: src/Data/MemPack/Error.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RecordWildCards #-}
-- |
-- Module : Data.MemPack.Error
-- Copyright : (c) Alexey Kuleshevich 2024-2025
-- License : BSD3
-- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>
-- Stability : experimental
-- Portability : non-portable
module Data.MemPack.Error where
import Control.Exception
import Data.List.NonEmpty as NE
import Data.Text (Text)
import Data.Typeable
import GHC.Exts
data SomeError where
SomeError :: (Typeable e, Error e) => e -> SomeError
instance Show SomeError where
showsPrec p (SomeError e) = showsPrec p e
instance Exception SomeError
-- | Very similar interface to `Exceptions`, except not intended for runtime exceptions.
class Show e => Error e where
toSomeError :: e -> SomeError
default toSomeError :: Typeable e => e -> SomeError
toSomeError = SomeError
fromSomeError :: SomeError -> Maybe e
default fromSomeError :: Typeable e => SomeError -> Maybe e
fromSomeError (SomeError t) = cast t
instance Error SomeError where
toSomeError = id
fromSomeError = Just
newtype TextError = TextError Text
deriving newtype (Eq, Show, IsString)
instance Error TextError
instance IsString SomeError where
fromString = toSomeError . TextError . fromString
newtype ManyErrors = ManyErrors (NonEmpty SomeError)
deriving (Show)
instance Error ManyErrors
data UnknownError = UnknownError
deriving (Show)
instance Error UnknownError
fromMultipleErrors :: [SomeError] -> SomeError
fromMultipleErrors es =
case es of
[] -> toSomeError UnknownError
[e] -> e
e : rest -> toSomeError $ ManyErrors (e :| rest)
{-# NOINLINE fromMultipleErrors #-}
data RanOutOfBytesError = RanOutOfBytesError
{ ranOutOfBytesRead :: Int
, ranOutOfBytesAvailable :: Int
, ranOutOfBytesRequested :: Int
}
deriving (Eq, Ord)
instance Show RanOutOfBytesError where
show RanOutOfBytesError{..} =
"Ran out of bytes. Read "
<> showBytes ranOutOfBytesRead
<> " out of "
<> showBytes ranOutOfBytesAvailable
<> ". Requested to read "
<> showBytes ranOutOfBytesRequested
<> " more."
instance Error RanOutOfBytesError
data NotFullyConsumedError = NotFullyConsumedError
{ notFullyConsumedRead :: Int
, notFullyConsumedAvailable :: Int
, notFullyConsumedTypeName :: String
}
deriving (Eq, Ord)
instance Show NotFullyConsumedError where
show NotFullyConsumedError{..} =
"Buffer of length " <> showBytes notFullyConsumedAvailable
++ " was not fully consumed while unpacking '" <> notFullyConsumedTypeName
++ "'. Unconsumed " <> showBytes (notFullyConsumedAvailable - notFullyConsumedRead)
++ " was leftover."
instance Error NotFullyConsumedError
showBytes :: Int -> String
showBytes 1 = "1 byte"
showBytes n = show n ++ " bytes"