{-# options_haddock prune #-}
module Ribosome.Host.Class.Msgpack.Error where
import Data.MessagePack (Object (..))
import qualified Data.Text as Text
import qualified Data.Text.Encoding.Error as UnicodeException
import Exon (exon)
import Log (Severity (Error))
import Numeric (showHex)
import Type.Reflection (typeRep)
import Ribosome.Host.Data.Report (Report (Report), Reportable (toReport))
data FieldError =
FieldError Text
|
NestedFieldError DecodeError
deriving stock (FieldError -> FieldError -> Bool
(FieldError -> FieldError -> Bool)
-> (FieldError -> FieldError -> Bool) -> Eq FieldError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FieldError -> FieldError -> Bool
$c/= :: FieldError -> FieldError -> Bool
== :: FieldError -> FieldError -> Bool
$c== :: FieldError -> FieldError -> Bool
Eq, Int -> FieldError -> ShowS
[FieldError] -> ShowS
FieldError -> String
(Int -> FieldError -> ShowS)
-> (FieldError -> String)
-> ([FieldError] -> ShowS)
-> Show FieldError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FieldError] -> ShowS
$cshowList :: [FieldError] -> ShowS
show :: FieldError -> String
$cshow :: FieldError -> String
showsPrec :: Int -> FieldError -> ShowS
$cshowsPrec :: Int -> FieldError -> ShowS
Show, (forall x. FieldError -> Rep FieldError x)
-> (forall x. Rep FieldError x -> FieldError) -> Generic FieldError
forall x. Rep FieldError x -> FieldError
forall x. FieldError -> Rep FieldError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep FieldError x -> FieldError
$cfrom :: forall x. FieldError -> Rep FieldError x
Generic)
instance IsString FieldError where
fromString :: String -> FieldError
fromString =
Text -> FieldError
FieldError (Text -> FieldError) -> (String -> Text) -> String -> FieldError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. IsString a => String -> a
fromString
data DecodeError =
DecodeError {
DecodeError -> Text
mainType :: Text,
DecodeError -> FieldError
fieldError :: FieldError
}
deriving stock (DecodeError -> DecodeError -> Bool
(DecodeError -> DecodeError -> Bool)
-> (DecodeError -> DecodeError -> Bool) -> Eq DecodeError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DecodeError -> DecodeError -> Bool
$c/= :: DecodeError -> DecodeError -> Bool
== :: DecodeError -> DecodeError -> Bool
$c== :: DecodeError -> DecodeError -> Bool
Eq, Int -> DecodeError -> ShowS
[DecodeError] -> ShowS
DecodeError -> String
(Int -> DecodeError -> ShowS)
-> (DecodeError -> String)
-> ([DecodeError] -> ShowS)
-> Show DecodeError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DecodeError] -> ShowS
$cshowList :: [DecodeError] -> ShowS
show :: DecodeError -> String
$cshow :: DecodeError -> String
showsPrec :: Int -> DecodeError -> ShowS
$cshowsPrec :: Int -> DecodeError -> ShowS
Show, (forall x. DecodeError -> Rep DecodeError x)
-> (forall x. Rep DecodeError x -> DecodeError)
-> Generic DecodeError
forall x. Rep DecodeError x -> DecodeError
forall x. DecodeError -> Rep DecodeError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep DecodeError x -> DecodeError
$cfrom :: forall x. DecodeError -> Rep DecodeError x
Generic)
compileError :: DecodeError -> (Text, Text)
compileError :: DecodeError -> (Text, Text)
compileError DecodeError
err =
([Text] -> Text) -> ([Text], Text) -> (Text, Text)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text -> [Text] -> Text
Text.intercalate Text
" within " ([Text] -> Text) -> ([Text] -> [Text]) -> [Text] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> [Text]
forall a. [a] -> [a]
reverse) (DecodeError -> ([Text], Text)
nest DecodeError
err)
where
nest :: DecodeError -> ([Text], Text)
nest DecodeError {Text
FieldError
fieldError :: FieldError
mainType :: Text
$sel:fieldError:DecodeError :: DecodeError -> FieldError
$sel:mainType:DecodeError :: DecodeError -> Text
..} =
([Text] -> [Text]) -> ([Text], Text) -> ([Text], Text)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text
mainType Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
:) (FieldError -> ([Text], Text)
field FieldError
fieldError)
field :: FieldError -> ([Text], Text)
field = \case
FieldError Text
msg ->
([], Text
msg)
NestedFieldError DecodeError
nerr ->
DecodeError -> ([Text], Text)
nest DecodeError
nerr
renderError :: DecodeError -> Text
renderError :: DecodeError -> Text
renderError DecodeError
err =
[exon|Decoding #{mainTypes}: #{fieldMsg}|]
where
(Text
mainTypes, Text
fieldMsg) =
DecodeError -> (Text, Text)
compileError DecodeError
err
instance Reportable DecodeError where
toReport :: DecodeError -> Report
toReport DecodeError
err =
HasCallStack => Text -> [Text] -> Severity -> Report
Text -> [Text] -> Severity -> Report
Report Text
msg [Text
Item [Text]
msg] Severity
Error
where
msg :: Text
msg =
DecodeError -> Text
renderError DecodeError
err
toDecodeError ::
∀ a .
Typeable a =>
Either FieldError a ->
Either DecodeError a
toDecodeError :: forall a. Typeable a => Either FieldError a -> Either DecodeError a
toDecodeError =
(FieldError -> DecodeError)
-> Either FieldError a -> Either DecodeError a
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text -> FieldError -> DecodeError
DecodeError (TypeRep a -> Text
forall b a. (Show a, IsString b) => a -> b
show (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a)))
decodeError ::
∀ a .
Typeable a =>
Text ->
Either DecodeError a
decodeError :: forall a. Typeable a => Text -> Either DecodeError a
decodeError Text
msg =
Either FieldError a -> Either DecodeError a
forall a. Typeable a => Either FieldError a -> Either DecodeError a
toDecodeError (FieldError -> Either FieldError a
forall a b. a -> Either a b
Left (Text -> FieldError
FieldError Text
msg))
symbolText ::
∀ a .
KnownSymbol a =>
Text
symbolText :: forall (a :: Symbol). KnownSymbol a => Text
symbolText =
String -> Text
forall a. ToText a => a -> Text
toText (Proxy a -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (forall {k} (t :: k). Proxy t
forall {t :: Symbol}. Proxy t
Proxy @a))
describe :: Object -> Text
describe :: Object -> Text
describe = \case
Object
ObjectNil -> Text
"Nil"
ObjectUInt Word64
_ -> Text
"UInt"
ObjectInt Int64
_ -> Text
"Int"
ObjectBool Bool
_ -> Text
"Bool"
ObjectFloat Float
_ -> Text
"Float"
ObjectDouble Double
_ -> Text
"Double"
ObjectString ByteString
_ -> Text
"String"
ObjectBinary ByteString
_ -> Text
"Binary"
ObjectArray [Object]
_ -> Text
"Array"
ObjectMap Map Object Object
_ -> Text
"Map"
ObjectExt Int8
_ ByteString
_ -> Text
"Ext"
incompatibleShapeError ::
Text ->
Text ->
FieldError
incompatibleShapeError :: Text -> Text -> FieldError
incompatibleShapeError Text
target Text
got =
Text -> FieldError
FieldError [exon|Got #{got} for #{target}|]
incompatibleShape ::
Text ->
Text ->
Either FieldError a
incompatibleShape :: forall a. Text -> Text -> Either FieldError a
incompatibleShape Text
target Text
got =
FieldError -> Either FieldError a
forall a b. a -> Either a b
Left (Text -> Text -> FieldError
incompatibleShapeError Text
target Text
got)
incompatibleCon ::
Text ->
Object ->
Either FieldError a
incompatibleCon :: forall a. Text -> Object -> Either FieldError a
incompatibleCon Text
target Object
o =
Text -> Text -> Either FieldError a
forall a. Text -> Text -> Either FieldError a
incompatibleShape Text
target (Object -> Text
describe Object
o)
incompatible ::
∀ a .
Typeable a =>
Object ->
Either FieldError a
incompatible :: forall a. Typeable a => Object -> Either FieldError a
incompatible =
Text -> Object -> Either FieldError a
forall a. Text -> Object -> Either FieldError a
incompatibleCon (TypeRep a -> Text
forall b a. (Show a, IsString b) => a -> b
show (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a))
decodeIncompatible ::
∀ a .
Typeable a =>
Object ->
Either DecodeError a
decodeIncompatible :: forall a. Typeable a => Object -> Either DecodeError a
decodeIncompatible Object
o =
Text -> Either DecodeError a
forall a. Typeable a => Text -> Either DecodeError a
decodeError [exon|Got #{describe o}|]
utf8Error :: UnicodeException -> FieldError
utf8Error :: UnicodeException -> FieldError
utf8Error = \case
UnicodeException.DecodeError String
_ (Just Word8
w) ->
Text -> FieldError
FieldError [exon|Invalid byte \x#{toText (showHex w "")}|]
UnicodeException.DecodeError String
_ Maybe Word8
Nothing ->
Text -> FieldError
FieldError Text
"Incomplete input"
UnicodeException
_ ->
Text -> FieldError
FieldError Text
"Impossible encode error"