2 -- (c) The University of Glasgow 2002-2006
6 {-# LANGUAGE ScopedTypeVariables #-}
8 -- * Main Serialized data type
12 -- * Going into and out of 'Serialized'
13 toSerialized, fromSerialized,
15 -- * Handy serialization functions
16 serializeWithData, deserializeWithData,
25 import Data.Word ( Word8 )
27 #if __GLASGOW_HASKELL__ > 609
35 -- | Represents a serialized value of a particular type. Attempts can be made to deserialize it at certain types
36 data Serialized = Serialized TypeRep [Word8]
38 instance Outputable Serialized where
39 ppr (Serialized the_type bytes) = int (length bytes) <+> ptext (sLit "of type") <+> text (show the_type)
41 instance Binary Serialized where
42 put_ bh (Serialized the_type bytes) = do
48 return (Serialized the_type bytes)
50 -- | Put a Typeable value that we are able to actually turn into bytes into a 'Serialized' value ready for deserialization later
51 toSerialized :: Typeable a => (a -> [Word8]) -> a -> Serialized
52 toSerialized serialize what = Serialized (typeOf what) (serialize what)
54 -- | If the 'Serialized' value contains something of the given type, then use the specified deserializer to return @Just@ that.
55 -- Otherwise return @Nothing@.
56 fromSerialized :: forall a. Typeable a => ([Word8] -> a) -> Serialized -> Maybe a
57 fromSerialized deserialize (Serialized the_type bytes)
58 | the_type == typeOf (undefined :: a) = Just (deserialize bytes)
61 -- | Force the contents of the Serialized value so weknow it doesn't contain any bottoms
62 seqSerialized :: Serialized -> ()
63 seqSerialized (Serialized the_type bytes) = the_type `seq` bytes `seqList` ()
66 -- | Use a 'Data' instance to implement a serialization scheme dual to that of 'deserializeWithData'
67 serializeWithData :: Data a => a -> [Word8]
68 serializeWithData what = serializeWithData' what []
70 serializeWithData' :: Data a => a -> [Word8] -> [Word8]
71 serializeWithData' what = fst $ gfoldl (\(before, a_to_b) a -> (before . serializeWithData' a, a_to_b a))
72 (\x -> (serializeConstr (constrRep (toConstr what)), x))
75 -- | Use a 'Data' instance to implement a deserialization scheme dual to that of 'serializeWithData'
76 deserializeWithData :: Data a => [Word8] -> a
77 deserializeWithData = snd . deserializeWithData'
79 deserializeWithData' :: forall a. Data a => [Word8] -> ([Word8], a)
80 deserializeWithData' bytes = deserializeConstr bytes $ \constr_rep bytes ->
81 gunfold (\(bytes, b_to_r) -> let (bytes', b) = deserializeWithData' bytes in (bytes', b_to_r b))
83 (repConstr (dataTypeOf (undefined :: a)) constr_rep)
86 serializeConstr :: ConstrRep -> [Word8] -> [Word8]
87 serializeConstr (AlgConstr ix) = serializeWord8 1 . serializeInt ix
88 serializeConstr (IntConstr i) = serializeWord8 2 . serializeInteger i
89 serializeConstr (FloatConstr r) = serializeWord8 3 . serializeRational r
90 #if __GLASGOW_HASKELL__ < 611
91 serializeConstr (StringConstr s) = serializeWord8 4 . serializeString s
93 serializeConstr (CharConstr c) = serializeWord8 4 . serializeChar c
97 deserializeConstr :: [Word8] -> (ConstrRep -> [Word8] -> a) -> a
98 deserializeConstr bytes k = deserializeWord8 bytes $ \constr_ix bytes ->
100 1 -> deserializeInt bytes $ \ix -> k (AlgConstr ix)
101 2 -> deserializeInteger bytes $ \i -> k (IntConstr i)
102 3 -> deserializeRational bytes $ \r -> k (FloatConstr r)
103 #if __GLASGOW_HASKELL__ >= 611
104 4 -> deserializeChar bytes $ \c -> k (CharConstr c)
106 4 -> deserializeString bytes $ \s -> k (StringConstr s)
108 x -> error $ "deserializeConstr: unrecognised serialized constructor type " ++ show x ++ " in context " ++ show bytes
111 serializeFixedWidthNum :: forall a. (Num a, Integral a, Bits a) => a -> [Word8] -> [Word8]
112 serializeFixedWidthNum what = go (bitSize what) what
114 go :: Int -> a -> [Word8] -> [Word8]
117 | otherwise = fromIntegral (current .&. 255) : go (size - 8) (current `shiftR` 8) rest
119 deserializeFixedWidthNum :: forall a b. (Num a, Integral a, Bits a) => [Word8] -> (a -> [Word8] -> b) -> b
120 deserializeFixedWidthNum bytes k = go (bitSize (undefined :: a)) bytes k
122 go :: Int -> [Word8] -> (a -> [Word8] -> b) -> b
124 | size <= 0 = k 0 bytes
125 | otherwise = case bytes of
126 (byte:bytes) -> go (size - 8) bytes (\x -> k ((x `shiftL` 8) .|. fromIntegral byte))
127 [] -> error "deserializeFixedWidthNum: unexpected end of stream"
130 serializeEnum :: (Enum a) => a -> [Word8] -> [Word8]
131 serializeEnum = serializeInt . fromEnum
133 deserializeEnum :: Enum a => [Word8] -> (a -> [Word8] -> b) -> b
134 deserializeEnum bytes k = deserializeInt bytes (k . toEnum)
137 serializeWord8 :: Word8 -> [Word8] -> [Word8]
138 serializeWord8 x = (x:)
140 deserializeWord8 :: [Word8] -> (Word8 -> [Word8] -> a) -> a
141 deserializeWord8 (byte:bytes) k = k byte bytes
142 deserializeWord8 [] _ = error "deserializeWord8: unexpected end of stream"
145 serializeInt :: Int -> [Word8] -> [Word8]
146 serializeInt = serializeFixedWidthNum
148 deserializeInt :: [Word8] -> (Int -> [Word8] -> a) -> a
149 deserializeInt = deserializeFixedWidthNum
152 serializeRational :: (Real a) => a -> [Word8] -> [Word8]
153 serializeRational = serializeString . show . toRational
155 deserializeRational :: (Fractional a) => [Word8] -> (a -> [Word8] -> b) -> b
156 deserializeRational bytes k = deserializeString bytes (k . fromRational . read)
159 serializeInteger :: Integer -> [Word8] -> [Word8]
160 serializeInteger = serializeString . show
162 deserializeInteger :: [Word8] -> (Integer -> [Word8] -> a) -> a
163 deserializeInteger bytes k = deserializeString bytes (k . read)
166 #if __GLASGOW_HASKELL__ >= 611
167 serializeChar :: Char -> [Word8] -> [Word8]
168 serializeChar = serializeString . show
170 deserializeChar :: [Word8] -> (Char -> [Word8] -> a) -> a
171 deserializeChar bytes k = deserializeString bytes (k . read)
175 serializeString :: String -> [Word8] -> [Word8]
176 serializeString = serializeList serializeEnum
178 deserializeString :: [Word8] -> (String -> [Word8] -> a) -> a
179 deserializeString = deserializeList deserializeEnum
182 serializeList :: (a -> [Word8] -> [Word8]) -> [a] -> [Word8] -> [Word8]
183 serializeList serialize_element xs = serializeInt (length xs) . foldr (.) id (map serialize_element xs)
185 deserializeList :: forall a b. (forall c. [Word8] -> (a -> [Word8] -> c) -> c)
186 -> [Word8] -> ([a] -> [Word8] -> b) -> b
187 deserializeList deserialize_element bytes k = deserializeInt bytes $ \len bytes -> go len bytes k
189 go :: Int -> [Word8] -> ([a] -> [Word8] -> b) -> b
191 | len <= 0 = k [] bytes
192 | otherwise = deserialize_element bytes (\elt bytes -> go (len - 1) bytes (k . (elt:)))