on 32785ad help sign in
361 lines 9.6 kB history raw
1-- |
2-- Module : Streamly.Internal.Serialize.ToBytes
3-- Copyright : (c) 2022 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : pre-release
7-- Portability : GHC
8--
9-- Encode Haskell data types to byte streams.
11module Streamly.Internal.Serialize.ToBytes
12 (
13 -- * Type class
14 ToBytes (..)
16 -- * Encoders
17 , unit
18 , bool
19 , ordering
20 , word8
21 , word16be
22 , word16le
23 , word32be
24 , word32le
25 , word64be
26 , word64le
27 , word64host
28 , int8
29 , int16be
30 , int16le
31 , int32be
32 , int32le
33 , int64be
34 , int64le
35 , float32be
36 , float32le
37 , double64be
38 , double64le
39 )
40where
42#include "MachDeps.h"
44import Data.Bits (shiftR)
45import Data.Word (Word8, Word16, Word32, Word64)
46import GHC.Float (castDoubleToWord64, castFloatToWord32)
47import Streamly.Internal.Data.Stream.StreamD (Stream)
48import Streamly.Internal.Data.Stream.StreamD (Step(..))
50import qualified Streamly.Internal.Data.Stream.StreamD as Stream
51import qualified Streamly.Internal.Data.Stream.StreamD as D
53import Data.Int (Int8, Int16, Int32, Int64)
55-- XXX Use StreamD directly?
57-- | A value of type '()' is encoded as @0@ in binary encoding.
58--
59-- @
60-- 0 ==> ()
61-- @
62--
63-- /Pre-release/
64--
65{-# INLINE unit #-}
66unit :: Applicative m => Stream m Word8
67unit = Stream.fromPure 0
69{-# INLINE boolToWord8 #-}
70boolToWord8 :: Bool -> Word8
71boolToWord8 False = 0
72boolToWord8 True = 1
74-- | A value of type 'Bool' is encoded as follows in binary encoding.
75--
76-- @
77-- 0 ==> False
78-- 1 ==> True
79-- @
80--
81-- /Pre-release/
82--
83{-# INLINE bool #-}
84bool :: Applicative m => Bool -> Stream m Word8
85bool = Stream.fromPure . boolToWord8
87{-# INLINE orderingToWord8 #-}
88orderingToWord8 :: Ordering -> Word8
89orderingToWord8 LT = 0
90orderingToWord8 EQ = 1
91orderingToWord8 GT = 2
93-- | A value of type 'Ordering' is encoded as follows in binary encoding.
94--
95-- @
96-- 0 ==> LT
97-- 1 ==> EQ
98-- 2 ==> GT
99-- @
100--
101-- /Pre-release/
102--
103{-# INLINE ordering #-}
104ordering :: Applicative m => Ordering -> Stream m Word8
105ordering = Stream.fromPure . orderingToWord8
107-- | Stream a 'Word8'.
108--
109-- /Pre-release/
110--
111{-# INLINE word8 #-}
112word8 :: Applicative m => Word8 -> Stream m Word8
113word8 = Stream.fromPure
115data W16State = W16B1 | W16B2 | W16Done
117{-# INLINE word16beD #-}
118word16beD :: Applicative m => Word16 -> D.Stream m Word8
119word16beD w = D.Stream step W16B1
121 where
123 step _ W16B1 = pure $ Yield (fromIntegral (shiftR w 8) :: Word8) W16B2
124 step _ W16B2 = pure $ Yield (fromIntegral w :: Word8) W16Done
125 step _ W16Done = pure Stop
127-- | Stream a 'Word16' as two bytes, the first byte is the MSB of the Word16
128-- and second byte is the LSB (big endian representation).
129--
130-- /Pre-release/
131--
132{-# INLINE word16be #-}
133word16be :: Monad m => Word16 -> Stream m Word8
134word16be = word16beD
136-- | Little endian (LSB first) Word16
137{-# INLINE word16leD #-}
138word16leD :: Applicative m => Word16 -> D.Stream m Word8
139word16leD w = D.Stream step W16B1
141 where
143 step _ W16B1 = pure $ Yield (fromIntegral w :: Word8) W16B2
144 step _ W16B2 = pure $ Yield (fromIntegral (shiftR w 8) :: Word8) W16Done
145 step _ W16Done = pure Stop
147-- | Stream a 'Word16' as two bytes, the first byte is the LSB of the Word16
148-- and second byte is the MSB (little endian representation).
149--
150-- /Pre-release/
151--
152{-# INLINE word16le #-}
153word16le :: Monad m => Word16 -> Stream m Word8
154word16le = word16leD
156data W32State = W32B1 | W32B2 | W32B3 | W32B4 | W32Done
158-- | Big endian (MSB first) Word32
159{-# INLINE word32beD #-}
160word32beD :: Applicative m => Word32 -> D.Stream m Word8
161word32beD w = D.Stream step W32B1
163 where
165 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
167 step _ W32B1 = yield 24 W32B2
168 step _ W32B2 = yield 16 W32B3
169 step _ W32B3 = yield 8 W32B4
170 step _ W32B4 = pure $ Yield (fromIntegral w :: Word8) W32Done
171 step _ W32Done = pure Stop
173-- | Stream a 'Word32' as four bytes, the first byte is the MSB of the Word32
174-- and last byte is the LSB (big endian representation).
175--
176-- /Pre-release/
177--
178{-# INLINE word32be #-}
179word32be :: Monad m => Word32 -> Stream m Word8
180word32be = word32beD
182-- | Little endian (LSB first) Word32
183{-# INLINE word32leD #-}
184word32leD :: Applicative m => Word32 -> D.Stream m Word8
185word32leD w = D.Stream step W32B1
187 where
189 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
191 step _ W32B1 = pure $ Yield (fromIntegral w :: Word8) W32B2
192 step _ W32B2 = yield 8 W32B3
193 step _ W32B3 = yield 16 W32B4
194 step _ W32B4 = yield 24 W32Done
195 step _ W32Done = pure Stop
197-- | Stream a 'Word32' as four bytes, the first byte is the MSB of the Word32
198-- and last byte is the LSB (big endian representation).
199--
200-- /Pre-release/
201--
202{-# INLINE word32le #-}
203word32le :: Monad m => Word32 -> Stream m Word8
204word32le = word32leD
206data W64State =
207 W64B1 | W64B2 | W64B3 | W64B4 | W64B5 | W64B6 | W64B7 | W64B8 | W64Done
209-- | Big endian (MSB first) Word64
210{-# INLINE word64beD #-}
211word64beD :: Applicative m => Word64 -> D.Stream m Word8
212word64beD w = D.Stream step W64B1
214 where
216 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
218 step _ W64B1 = yield 56 W64B2
219 step _ W64B2 = yield 48 W64B3
220 step _ W64B3 = yield 40 W64B4
221 step _ W64B4 = yield 32 W64B5
222 step _ W64B5 = yield 24 W64B6
223 step _ W64B6 = yield 16 W64B7
224 step _ W64B7 = yield 8 W64B8
225 step _ W64B8 = pure $ Yield (fromIntegral w :: Word8) W64Done
226 step _ W64Done = pure Stop
228-- | Stream a 'Word64' as eight bytes, the first byte is the MSB of the Word64
229-- and last byte is the LSB (big endian representation).
230--
231-- /Pre-release/
232--
233{-# INLINE word64be #-}
234word64be :: Monad m => Word64 -> Stream m Word8
235word64be = word64beD
237-- | Little endian (LSB first) Word64
238{-# INLINE word64leD #-}
239word64leD :: Applicative m => Word64 -> D.Stream m Word8
240word64leD w = D.Stream step W64B1
242 where
244 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
246 step _ W64B1 = pure $ Yield (fromIntegral w :: Word8) W64B2
247 step _ W64B2 = yield 8 W64B3
248 step _ W64B3 = yield 16 W64B4
249 step _ W64B4 = yield 24 W64B5
250 step _ W64B5 = yield 32 W64B6
251 step _ W64B6 = yield 40 W64B7
252 step _ W64B7 = yield 48 W64B8
253 step _ W64B8 = yield 56 W64Done
254 step _ W64Done = pure Stop
256-- | Stream a 'Word64' as eight bytes, the first byte is the MSB of the Word64
257-- and last byte is the LSB (big endian representation).
258--
259-- /Pre-release/
260--
261{-# INLINE word64le #-}
262word64le :: Monad m => Word64 -> Stream m Word8
263word64le = word64leD
265{-# INLINE int8 #-}
266int8 :: Applicative m => Int8 -> Stream m Word8
267int8 i = word8 (fromIntegral i :: Word8)
269-- | Stream a 'Int16' as two bytes, the first byte is the MSB of the Int16
270-- and second byte is the LSB (big endian representation).
271--
272-- /Pre-release/
273--
274{-# INLINE int16be #-}
275int16be :: Monad m => Int16 -> Stream m Word8
276int16be i = word16be (fromIntegral i :: Word16)
278-- | Stream a 'Int16' as two bytes, the first byte is the LSB of the Int16
279-- and second byte is the MSB (little endian representation).
280--
281-- /Pre-release/
282--
283{-# INLINE int16le #-}
284int16le :: Monad m => Int16 -> Stream m Word8
285int16le i = word16le (fromIntegral i :: Word16)
287-- | Stream a 'Int32' as four bytes, the first byte is the MSB of the Int32
288-- and last byte is the LSB (big endian representation).
289--
290-- /Pre-release/
291--
292{-# INLINE int32be #-}
293int32be :: Monad m => Int32 -> Stream m Word8
294int32be i = word32be (fromIntegral i :: Word32)
296{-# INLINE int32le #-}
297int32le :: Monad m => Int32 -> Stream m Word8
298int32le i = word32le (fromIntegral i :: Word32)
300-- | Stream a 'Int64' as eight bytes, the first byte is the MSB of the Int64
301-- and last byte is the LSB (big endian representation).
302--
303-- /Pre-release/
304--
305{-# INLINE int64be #-}
306int64be :: Monad m => Int64 -> Stream m Word8
307int64be i = word64be (fromIntegral i :: Word64)
309-- | Stream a 'Int64' as eight bytes, the first byte is the LSB of the Int64
310-- and last byte is the MSB (little endian representation).
311--
312-- /Pre-release/
313--
314{-# INLINE int64le #-}
315int64le :: Monad m => Int64 -> Stream m Word8
316int64le i = word64le (fromIntegral i :: Word64)
318-- | Big endian (MSB first) Float
319{-# INLINE float32be #-}
320float32be :: Monad m => Float -> Stream m Word8
321float32be = word32beD . castFloatToWord32
323-- | Little endian (LSB first) Float
324{-# INLINE float32le #-}
325float32le :: Monad m => Float -> Stream m Word8
326float32le = word32leD . castFloatToWord32
328-- | Big endian (MSB first) Double
329{-# INLINE double64be #-}
330double64be :: Monad m => Double -> Stream m Word8
331double64be = word64beD . castDoubleToWord64
333-- | Little endian (LSB first) Double
334{-# INLINE double64le #-}
335double64le :: Monad m => Double -> Stream m Word8
336double64le = word64leD . castDoubleToWord64
338-------------------------------------------------------------------------------
339-- Host byte order
340-------------------------------------------------------------------------------
342-- | Stream a 'Word64' as eight bytes in the host byte order.
343--
344-- /Pre-release/
345--
346{-# INLINE word64host #-}
347word64host :: Monad m => Word64 -> Stream m Word8
348word64host =
349#ifdef WORDS_BIGENDIAN
350 word64be
351#else
352 word64le
353#endif
355-------------------------------------------------------------------------------
356-- Type class
357-------------------------------------------------------------------------------
359class ToBytes a where
360 -- | Convert a Haskell type to a byte stream.
361 toBytes :: a -> Stream m Word8