TokTok / hs-msgpack-binary

Haskell implementation of MessagePack / msgpack.org
http://msgpack.org/
Other
16 stars 10 forks source link

`user error (invalid encoding for list)` on unpacking a listless structure #75

Closed l29ah closed 2 years ago

l29ah commented 4 years ago

I'm trying to unpack msgpack into my type that has no lists:

data UniverseView = UniverseView
    { planets :: Object
    , star_systems :: Object
    , current_id :: Object
    , empires :: Object
    , planets_in_star_systems :: Object
    , starlanes :: Object
    , star_systems_in_empires :: Object
    , ships :: Object
    , ships_in_star_systems :: Object
    , ships_in_empires :: Object
    , controlled_empire :: Object
    --, turn_number :: Word
    , turn_number :: Object
    } deriving (Show, Eq, Generic)

instance MessagePack UniverseView

On running my program, i get this:

*** Exception (reporting due to +RTS -xc): (THUNK_1_0), stack trace: 
  Data.MessagePack.unpack,
  called from Main.rpc,
  called from Main.main
test: user error (invalid encoding for list)

This behaviour seems incorrect. The code employed is

    decRetVal <- unpack $ BL.fromStrict retVal
    --print $ (decRetVal :: Object)
    print $ (decRetVal :: UniverseView)

It woks ok if i decode it as an Object. The printed Object has a top-level array with the same number of items as my data type: http://dpaste.com/0F6045T

l29ah commented 4 years ago

After printing a packed test UniverseView filled with ObjectNil's i'm totally confused:

ObjectArray [ObjectArray [ObjectArray [ObjectNil,ObjectNil,ObjectNil],ObjectNil,ObjectNil,ObjectNil],ObjectArray [ObjectNil,ObjectNil,ObjectNil],ObjectNil,ObjectNil,ObjectNil]

Why wasn't it placed in a flat array?

l29ah commented 4 years ago

M1 {unM1 = M1 {unM1 = ((M1 {unM1 = K1 {unK1 = ObjectInt 0}} :: (M1 {unM1 = K1 {unK1 = ObjectInt 1}} :: M1 {unM1 = K1 {unK1 = ObjectInt 2}})) :: (M1 {unM1 = K1 {unK1 = ObjectInt 3}} :: (M1 {unM1 = K1 {unK1 = ObjectInt 4}} :: M1 {unM1 = K1 {unK1 = ObjectInt 5}}))) :: ((M1 {unM1 = K1 {unK1 = ObjectInt 6}} :: (M1 {unM1 = K1 {unK1 = ObjectInt 7}} :: M1 {unM1 = K1 {unK1 = ObjectInt 8}})) :: (M1 {unM1 = K1 {unK1 = ObjectInt 9}} :: (M1 {unM1 = K1 {unK1 = ObjectInt 10}} :*: M1 {unM1 = K1 {unK1 = ObjectInt 11}})))}}

mmkay; i wonder if the simplest solution would be rewriting it in https://hackage.haskell.org/package/generics-sop, as i don't see how to flatten this properly; i have no experience with generics tho.

l29ah commented 4 years ago

I've "fixed" serializing with

diff --git a/src/Data/MessagePack/Types/Generic.hs b/src/Data/MessagePack/Types/Generic.hs
index 059971b..91fc305 100644
--- a/src/Data/MessagePack/Types/Generic.hs
+++ b/src/Data/MessagePack/Types/Generic.hs
@@ -8,6 +8,7 @@
 {-# LANGUAGE Safe                #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeOperators       #-}
+{-# LANGUAGE  UndecidableInstances #-}
 module Data.MessagePack.Types.Generic () where

 import           Control.Applicative           (Applicative, (<$>), (<*>))
@@ -28,7 +29,7 @@ instance GMessagePack U1 where
     gFromObject ObjectNil = return U1
     gFromObject _         = fail "invalid encoding for custom unit type"

-instance (GMessagePack a, GProdPack b) => GMessagePack (a :*: b) where
+instance (GProdPack a) => GMessagePack (a) where
     gToObject   = toObject . prodToObject
     gFromObject = fromObject >=> prodFromObject

@@ -65,8 +66,8 @@ class GProdPack f where
         -> m (f a)

-instance (GMessagePack a, GProdPack b) => GProdPack (a :*: b) where
-    prodToObject (a :*: b) = gToObject a : prodToObject b
+instance (GProdPack a, GProdPack b) => GProdPack (a :*: b) where
+    prodToObject (a :*: b) = prodToObject a ++ prodToObject b
     prodFromObject (a : b) = (:*:) <$> gFromObject a <*> prodFromObject b
     prodFromObject []      = fail "invalid encoding for product type"

but deserializing is broken.