on c4794aa help sign in
158 lines 5.7 kB history raw
1module Streamly.Internal.Data.Serialize
2 ( Size(..)
3 , Serialize(..)
4 ) where
6--------------------------------------------------------------------------------
7-- Imports
8--------------------------------------------------------------------------------
10import Control.Monad (void)
11import Data.List (foldl')
12import Data.Proxy (Proxy (..))
13import Streamly.Internal.Data.Unbox (MutableByteArray(..))
15import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
16import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
17import GHC.Stable (StablePtr(..))
19import qualified Streamly.Internal.Data.Unbox as Unbox
21import GHC.Exts
23--------------------------------------------------------------------------------
24-- Types
25--------------------------------------------------------------------------------
27-- | Info about the length of a serializable type. Length can depend on the
28-- value or can be independent.
29data Size a
30 = VarSize (a -> Int)
31 | ConstSize !Int
33-- | A type implementing the 'Serialize' interface supplies operations for
34-- reading and writing the type from and to a mutable byte array (an unboxed
35-- representation of the type) in memory. The read operation 'deserialize'
36-- deserializes the boxed type from the mutable byte array. The write operation
37-- 'serialize' serializes the boxed type to the mutable byte array.
38--
39-- IMPORTANT: The serialized data's byte ordering is not normalized, which means
40-- it remains the same as the machine's byte order where the function is
41-- executed. Consequently, it may not be compatible across machines with
42-- different byte ordering.
43--
44-- 'Serialize' contains enough information to serialize and deserialize variable
45-- length types.
46--
47-- >>> import Streamly.Internal.Data.Serialize (Serialize(..), Size(..))
48--
49-- >>> :{
50-- data Object = Object
51-- { _varLen :: [Int]
52-- , _constLen :: Int
53-- }
54-- :}
55--
56-- >>> :{
57-- instance Serialize Object where
58-- size =
59-- case (size :: Size [Int], size :: Size Int) of
60-- (VarSize f, ConstSize g) ->
61-- VarSize $ \obj ->
62-- f (_varLen obj) + g
63-- _ -> error "size is not defined properly"
64-- deserialize i arr = do
65-- (i1, x0) <- deserialize i arr
66-- (i2, x1) <- deserialize i1 arr
67-- pure (i2, Object x0 x1)
68-- serialize i arr (Object x0 x1) = do
69-- i1 <- serialize i arr x0
70-- i2 <- serialize i1 arr x1
71-- pure i2
72-- :}
73--
74class Serialize a where
75 -- | Get the 'Size', in bytes, reqired to store the serialized
76 -- representation of the type. Size cannot be zero.
77 size :: Size a
79 -- We can implement the following functions without returning the `Int`
80 -- offset but that may require traversing the Haskell structure again to get
81 -- the size. Therefore, this is a performance optimization.
83 -- | Deserialize a value from the given byte-index in the array. Returns a
84 -- tuple of the next byte-index and the deserialized value.
85 deserialize :: Int -> MutableByteArray -> IO (Int, a)
87 -- | Write the serialized representation of the value in the array at the
88 -- given byte-index. Returns the next byte-index.
89 serialize :: Int -> MutableByteArray -> a -> IO Int
91--------------------------------------------------------------------------------
92-- Instances
93--------------------------------------------------------------------------------
95#define DERIVE_SERIALIZE_FROM_UNBOX(_type) \
96instance Serialize _type where \
97; size = ConstSize $ Unbox.sizeOf (Proxy :: Proxy _type) \
98; deserialize off arr = \
99 Unbox.peekByteIndex off arr >>= \
100 \val -> let sz = Unbox.sizeOf (Proxy :: Proxy _type) \
101 in pure (off + sz, val) \
102; serialize off arr val = \
103 Unbox.pokeByteIndex off arr val \
104 >> let sz = Unbox.sizeOf (Proxy :: Proxy _type) \
105 in pure (off + sz)
107DERIVE_SERIALIZE_FROM_UNBOX(Bool)
108DERIVE_SERIALIZE_FROM_UNBOX(Char)
109DERIVE_SERIALIZE_FROM_UNBOX(Int8)
110DERIVE_SERIALIZE_FROM_UNBOX(Int16)
111DERIVE_SERIALIZE_FROM_UNBOX(Int32)
112DERIVE_SERIALIZE_FROM_UNBOX(Int)
113DERIVE_SERIALIZE_FROM_UNBOX(Int64)
114DERIVE_SERIALIZE_FROM_UNBOX(Word)
115DERIVE_SERIALIZE_FROM_UNBOX(Word8)
116DERIVE_SERIALIZE_FROM_UNBOX(Word16)
117DERIVE_SERIALIZE_FROM_UNBOX(Word32)
118DERIVE_SERIALIZE_FROM_UNBOX(Word64)
119DERIVE_SERIALIZE_FROM_UNBOX(Double)
120DERIVE_SERIALIZE_FROM_UNBOX(Float)
121DERIVE_SERIALIZE_FROM_UNBOX((StablePtr a))
122DERIVE_SERIALIZE_FROM_UNBOX((Ptr a))
123DERIVE_SERIALIZE_FROM_UNBOX((FunPtr a))
125instance forall a. Serialize a => Serialize [a] where
127 {-# INLINE size #-}
128 size = VarSize $ \lst ->
129 case size :: Size a of
130 VarSize f ->
131 foldl'
132 (\acc x -> acc + f x)
133 (Unbox.sizeOf (Proxy :: Proxy Int))
134 lst
135 ConstSize sz ->
136 length lst
137 * sz
138 + Unbox.sizeOf (Proxy :: Proxy Int)
140 {-# INLINE deserialize #-}
141 deserialize off arr = do
142 len <- Unbox.peekByteIndex off arr :: IO Int
143 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Int)
144 let peekList buf o 0 = pure (o, reverse buf)
145 peekList buf o i = do
146 (o1, x) <- deserialize o arr
147 peekList (x:buf) o1 (i - 1)
148 peekList [] off1 len
150 {-# INLINE serialize #-}
151 serialize off arr val = do
152 void $ serialize off arr (length val)
153 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Int)
154 let pokeList o [] = pure o
155 pokeList o (x:xs) = do
156 o1 <- serialize o arr x
157 pokeList o1 xs
158 pokeList off1 val