on dddee88 help sign in
374 lines 10.0 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 , charLatin1
40 , charUtf8
41 )
42where
44#include "MachDeps.h"
46import Data.Bits (shiftR)
47import Data.Char (ord)
48import Data.Int (Int8, Int16, Int32, Int64)
49import Data.Word (Word8, Word16, Word32, Word64)
50import GHC.Float (castDoubleToWord64, castFloatToWord32)
51import Streamly.Internal.Data.Stream.StreamD (Stream)
52import Streamly.Internal.Data.Stream.StreamD (Step(..))
53import Streamly.Internal.Unicode.Stream (readCharUtf8)
55import qualified Streamly.Internal.Data.Stream.StreamD as Stream
56import qualified Streamly.Internal.Data.Stream.StreamD as D
58-- XXX Use StreamD directly?
60-- | A value of type '()' is encoded as @0@ in binary encoding.
61--
62-- @
63-- 0 ==> ()
64-- @
65--
66-- /Pre-release/
67--
68{-# INLINE unit #-}
69unit :: Applicative m => Stream m Word8
70unit = Stream.fromPure 0
72{-# INLINE boolToWord8 #-}
73boolToWord8 :: Bool -> Word8
74boolToWord8 False = 0
75boolToWord8 True = 1
77-- | A value of type 'Bool' is encoded as follows in binary encoding.
78--
79-- @
80-- 0 ==> False
81-- 1 ==> True
82-- @
83--
84-- /Pre-release/
85--
86{-# INLINE bool #-}
87bool :: Applicative m => Bool -> Stream m Word8
88bool = Stream.fromPure . boolToWord8
90{-# INLINE orderingToWord8 #-}
91orderingToWord8 :: Ordering -> Word8
92orderingToWord8 LT = 0
93orderingToWord8 EQ = 1
94orderingToWord8 GT = 2
96-- | A value of type 'Ordering' is encoded as follows in binary encoding.
97--
98-- @
99-- 0 ==> LT
100-- 1 ==> EQ
101-- 2 ==> GT
102-- @
103--
104-- /Pre-release/
105--
106{-# INLINE ordering #-}
107ordering :: Applicative m => Ordering -> Stream m Word8
108ordering = Stream.fromPure . orderingToWord8
110-- | Stream a 'Word8'.
111--
112-- /Pre-release/
113--
114{-# INLINE word8 #-}
115word8 :: Applicative m => Word8 -> Stream m Word8
116word8 = Stream.fromPure
118data W16State = W16B1 | W16B2 | W16Done
120{-# INLINE word16beD #-}
121word16beD :: Applicative m => Word16 -> D.Stream m Word8
122word16beD w = D.Stream step W16B1
124 where
126 step _ W16B1 = pure $ Yield (fromIntegral (shiftR w 8) :: Word8) W16B2
127 step _ W16B2 = pure $ Yield (fromIntegral w :: Word8) W16Done
128 step _ W16Done = pure Stop
130-- | Stream a 'Word16' as two bytes, the first byte is the MSB of the Word16
131-- and second byte is the LSB (big endian representation).
132--
133-- /Pre-release/
134--
135{-# INLINE word16be #-}
136word16be :: Monad m => Word16 -> Stream m Word8
137word16be = word16beD
139-- | Little endian (LSB first) Word16
140{-# INLINE word16leD #-}
141word16leD :: Applicative m => Word16 -> D.Stream m Word8
142word16leD w = D.Stream step W16B1
144 where
146 step _ W16B1 = pure $ Yield (fromIntegral w :: Word8) W16B2
147 step _ W16B2 = pure $ Yield (fromIntegral (shiftR w 8) :: Word8) W16Done
148 step _ W16Done = pure Stop
150-- | Stream a 'Word16' as two bytes, the first byte is the LSB of the Word16
151-- and second byte is the MSB (little endian representation).
152--
153-- /Pre-release/
154--
155{-# INLINE word16le #-}
156word16le :: Monad m => Word16 -> Stream m Word8
157word16le = word16leD
159data W32State = W32B1 | W32B2 | W32B3 | W32B4 | W32Done
161-- | Big endian (MSB first) Word32
162{-# INLINE word32beD #-}
163word32beD :: Applicative m => Word32 -> D.Stream m Word8
164word32beD w = D.Stream step W32B1
166 where
168 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
170 step _ W32B1 = yield 24 W32B2
171 step _ W32B2 = yield 16 W32B3
172 step _ W32B3 = yield 8 W32B4
173 step _ W32B4 = pure $ Yield (fromIntegral w :: Word8) W32Done
174 step _ W32Done = pure Stop
176-- | Stream a 'Word32' as four bytes, the first byte is the MSB of the Word32
177-- and last byte is the LSB (big endian representation).
178--
179-- /Pre-release/
180--
181{-# INLINE word32be #-}
182word32be :: Monad m => Word32 -> Stream m Word8
183word32be = word32beD
185-- | Little endian (LSB first) Word32
186{-# INLINE word32leD #-}
187word32leD :: Applicative m => Word32 -> D.Stream m Word8
188word32leD w = D.Stream step W32B1
190 where
192 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
194 step _ W32B1 = pure $ Yield (fromIntegral w :: Word8) W32B2
195 step _ W32B2 = yield 8 W32B3
196 step _ W32B3 = yield 16 W32B4
197 step _ W32B4 = yield 24 W32Done
198 step _ W32Done = pure Stop
200-- | Stream a 'Word32' as four bytes, the first byte is the MSB of the Word32
201-- and last byte is the LSB (big endian representation).
202--
203-- /Pre-release/
204--
205{-# INLINE word32le #-}
206word32le :: Monad m => Word32 -> Stream m Word8
207word32le = word32leD
209data W64State =
210 W64B1 | W64B2 | W64B3 | W64B4 | W64B5 | W64B6 | W64B7 | W64B8 | W64Done
212-- | Big endian (MSB first) Word64
213{-# INLINE word64beD #-}
214word64beD :: Applicative m => Word64 -> D.Stream m Word8
215word64beD w = D.Stream step W64B1
217 where
219 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
221 step _ W64B1 = yield 56 W64B2
222 step _ W64B2 = yield 48 W64B3
223 step _ W64B3 = yield 40 W64B4
224 step _ W64B4 = yield 32 W64B5
225 step _ W64B5 = yield 24 W64B6
226 step _ W64B6 = yield 16 W64B7
227 step _ W64B7 = yield 8 W64B8
228 step _ W64B8 = pure $ Yield (fromIntegral w :: Word8) W64Done
229 step _ W64Done = pure Stop
231-- | Stream a 'Word64' as eight bytes, the first byte is the MSB of the Word64
232-- and last byte is the LSB (big endian representation).
233--
234-- /Pre-release/
235--
236{-# INLINE word64be #-}
237word64be :: Monad m => Word64 -> Stream m Word8
238word64be = word64beD
240-- | Little endian (LSB first) Word64
241{-# INLINE word64leD #-}
242word64leD :: Applicative m => Word64 -> D.Stream m Word8
243word64leD w = D.Stream step W64B1
245 where
247 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
249 step _ W64B1 = pure $ Yield (fromIntegral w :: Word8) W64B2
250 step _ W64B2 = yield 8 W64B3
251 step _ W64B3 = yield 16 W64B4
252 step _ W64B4 = yield 24 W64B5
253 step _ W64B5 = yield 32 W64B6
254 step _ W64B6 = yield 40 W64B7
255 step _ W64B7 = yield 48 W64B8
256 step _ W64B8 = yield 56 W64Done
257 step _ W64Done = pure Stop
259-- | Stream a 'Word64' as eight bytes, the first byte is the MSB of the Word64
260-- and last byte is the LSB (big endian representation).
261--
262-- /Pre-release/
263--
264{-# INLINE word64le #-}
265word64le :: Monad m => Word64 -> Stream m Word8
266word64le = word64leD
268{-# INLINE int8 #-}
269int8 :: Applicative m => Int8 -> Stream m Word8
270int8 i = word8 (fromIntegral i :: Word8)
272-- | Stream a 'Int16' as two bytes, the first byte is the MSB of the Int16
273-- and second byte is the LSB (big endian representation).
274--
275-- /Pre-release/
276--
277{-# INLINE int16be #-}
278int16be :: Monad m => Int16 -> Stream m Word8
279int16be i = word16be (fromIntegral i :: Word16)
281-- | Stream a 'Int16' as two bytes, the first byte is the LSB of the Int16
282-- and second byte is the MSB (little endian representation).
283--
284-- /Pre-release/
285--
286{-# INLINE int16le #-}
287int16le :: Monad m => Int16 -> Stream m Word8
288int16le i = word16le (fromIntegral i :: Word16)
290-- | Stream a 'Int32' as four bytes, the first byte is the MSB of the Int32
291-- and last byte is the LSB (big endian representation).
292--
293-- /Pre-release/
294--
295{-# INLINE int32be #-}
296int32be :: Monad m => Int32 -> Stream m Word8
297int32be i = word32be (fromIntegral i :: Word32)
299{-# INLINE int32le #-}
300int32le :: Monad m => Int32 -> Stream m Word8
301int32le i = word32le (fromIntegral i :: Word32)
303-- | Stream a 'Int64' as eight bytes, the first byte is the MSB of the Int64
304-- and last byte is the LSB (big endian representation).
305--
306-- /Pre-release/
307--
308{-# INLINE int64be #-}
309int64be :: Monad m => Int64 -> Stream m Word8
310int64be i = word64be (fromIntegral i :: Word64)
312-- | Stream a 'Int64' as eight bytes, the first byte is the LSB of the Int64
313-- and last byte is the MSB (little endian representation).
314--
315-- /Pre-release/
316--
317{-# INLINE int64le #-}
318int64le :: Monad m => Int64 -> Stream m Word8
319int64le i = word64le (fromIntegral i :: Word64)
321-- | Big endian (MSB first) Float
322{-# INLINE float32be #-}
323float32be :: Monad m => Float -> Stream m Word8
324float32be = word32beD . castFloatToWord32
326-- | Little endian (LSB first) Float
327{-# INLINE float32le #-}
328float32le :: Monad m => Float -> Stream m Word8
329float32le = word32leD . castFloatToWord32
331-- | Big endian (MSB first) Double
332{-# INLINE double64be #-}
333double64be :: Monad m => Double -> Stream m Word8
334double64be = word64beD . castDoubleToWord64
336-- | Little endian (LSB first) Double
337{-# INLINE double64le #-}
338double64le :: Monad m => Double -> Stream m Word8
339double64le = word64leD . castDoubleToWord64
341-- | Encode a Unicode character to stream of bytes in 0-255 range.
342--
343{-# INLINE charLatin1 #-}
344charLatin1 :: Applicative m => Char -> Stream m Word8
345charLatin1 = Stream.fromPure . fromIntegral . ord
347{-# INLINE charUtf8 #-}
348charUtf8 :: Monad m => Char -> Stream m Word8
349charUtf8 = Stream.unfold readCharUtf8
351-------------------------------------------------------------------------------
352-- Host byte order
353-------------------------------------------------------------------------------
355-- | Stream a 'Word64' as eight bytes in the host byte order.
356--
357-- /Pre-release/
358--
359{-# INLINE word64host #-}
360word64host :: Monad m => Word64 -> Stream m Word8
361word64host =
362#ifdef WORDS_BIGENDIAN
363 word64be
364#else
365 word64le
366#endif
368-------------------------------------------------------------------------------
369-- Type class
370-------------------------------------------------------------------------------
372class ToBytes a where
373 -- | Convert a Haskell type to a byte stream.
374 toBytes :: a -> Stream m Word8