on d29030f help sign in
373 lines 9.9 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-- Portability : GHC
7--
8-- Encode Haskell data types to byte streams.
10module Streamly.Internal.Serialize.ToBytes
11 (
12 -- * Type class
13 ToBytes (..)
15 -- * Encoders
16 , unit
17 , bool
18 , ordering
19 , word8
20 , word16be
21 , word16le
22 , word32be
23 , word32le
24 , word64be
25 , word64le
26 , word64host
27 , int8
28 , int16be
29 , int16le
30 , int32be
31 , int32le
32 , int64be
33 , int64le
34 , float32be
35 , float32le
36 , double64be
37 , double64le
38 , charLatin1
39 , charUtf8
40 )
41where
43#include "MachDeps.h"
45import Data.Bits (shiftR)
46import Data.Char (ord)
47import Data.Int (Int8, Int16, Int32, Int64)
48import Data.Word (Word8, Word16, Word32, Word64)
49import GHC.Float (castDoubleToWord64, castFloatToWord32)
50import Streamly.Internal.Data.Stream (Stream)
51import Streamly.Internal.Data.Stream (Step(..))
52import Streamly.Internal.Unicode.Stream (readCharUtf8)
54import qualified Streamly.Internal.Data.Stream as Stream
55import qualified Streamly.Internal.Data.Stream as D
57-- XXX Use StreamD directly?
59-- | A value of type '()' is encoded as @0@ in binary encoding.
60--
61-- @
62-- 0 ==> ()
63-- @
64--
65-- /Pre-release/
66--
67{-# INLINE unit #-}
68unit :: Applicative m => Stream m Word8
69unit = Stream.fromPure 0
71{-# INLINE boolToWord8 #-}
72boolToWord8 :: Bool -> Word8
73boolToWord8 False = 0
74boolToWord8 True = 1
76-- | A value of type 'Bool' is encoded as follows in binary encoding.
77--
78-- @
79-- 0 ==> False
80-- 1 ==> True
81-- @
82--
83-- /Pre-release/
84--
85{-# INLINE bool #-}
86bool :: Applicative m => Bool -> Stream m Word8
87bool = Stream.fromPure . boolToWord8
89{-# INLINE orderingToWord8 #-}
90orderingToWord8 :: Ordering -> Word8
91orderingToWord8 LT = 0
92orderingToWord8 EQ = 1
93orderingToWord8 GT = 2
95-- | A value of type 'Ordering' is encoded as follows in binary encoding.
96--
97-- @
98-- 0 ==> LT
99-- 1 ==> EQ
100-- 2 ==> GT
101-- @
102--
103-- /Pre-release/
104--
105{-# INLINE ordering #-}
106ordering :: Applicative m => Ordering -> Stream m Word8
107ordering = Stream.fromPure . orderingToWord8
109-- | Stream a 'Word8'.
110--
111-- /Pre-release/
112--
113{-# INLINE word8 #-}
114word8 :: Applicative m => Word8 -> Stream m Word8
115word8 = Stream.fromPure
117data W16State = W16B1 | W16B2 | W16Done
119{-# INLINE word16beD #-}
120word16beD :: Applicative m => Word16 -> D.Stream m Word8
121word16beD w = D.Stream step W16B1
123 where
125 step _ W16B1 = pure $ Yield (fromIntegral (shiftR w 8) :: Word8) W16B2
126 step _ W16B2 = pure $ Yield (fromIntegral w :: Word8) W16Done
127 step _ W16Done = pure Stop
129-- | Stream a 'Word16' as two bytes, the first byte is the MSB of the Word16
130-- and second byte is the LSB (big endian representation).
131--
132-- /Pre-release/
133--
134{-# INLINE word16be #-}
135word16be :: Monad m => Word16 -> Stream m Word8
136word16be = word16beD
138-- | Little endian (LSB first) Word16
139{-# INLINE word16leD #-}
140word16leD :: Applicative m => Word16 -> D.Stream m Word8
141word16leD w = D.Stream step W16B1
143 where
145 step _ W16B1 = pure $ Yield (fromIntegral w :: Word8) W16B2
146 step _ W16B2 = pure $ Yield (fromIntegral (shiftR w 8) :: Word8) W16Done
147 step _ W16Done = pure Stop
149-- | Stream a 'Word16' as two bytes, the first byte is the LSB of the Word16
150-- and second byte is the MSB (little endian representation).
151--
152-- /Pre-release/
153--
154{-# INLINE word16le #-}
155word16le :: Monad m => Word16 -> Stream m Word8
156word16le = word16leD
158data W32State = W32B1 | W32B2 | W32B3 | W32B4 | W32Done
160-- | Big endian (MSB first) Word32
161{-# INLINE word32beD #-}
162word32beD :: Applicative m => Word32 -> D.Stream m Word8
163word32beD w = D.Stream step W32B1
165 where
167 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
169 step _ W32B1 = yield 24 W32B2
170 step _ W32B2 = yield 16 W32B3
171 step _ W32B3 = yield 8 W32B4
172 step _ W32B4 = pure $ Yield (fromIntegral w :: Word8) W32Done
173 step _ W32Done = pure Stop
175-- | Stream a 'Word32' as four bytes, the first byte is the MSB of the Word32
176-- and last byte is the LSB (big endian representation).
177--
178-- /Pre-release/
179--
180{-# INLINE word32be #-}
181word32be :: Monad m => Word32 -> Stream m Word8
182word32be = word32beD
184-- | Little endian (LSB first) Word32
185{-# INLINE word32leD #-}
186word32leD :: Applicative m => Word32 -> D.Stream m Word8
187word32leD w = D.Stream step W32B1
189 where
191 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
193 step _ W32B1 = pure $ Yield (fromIntegral w :: Word8) W32B2
194 step _ W32B2 = yield 8 W32B3
195 step _ W32B3 = yield 16 W32B4
196 step _ W32B4 = yield 24 W32Done
197 step _ W32Done = pure Stop
199-- | Stream a 'Word32' as four bytes, the first byte is the MSB of the Word32
200-- and last byte is the LSB (big endian representation).
201--
202-- /Pre-release/
203--
204{-# INLINE word32le #-}
205word32le :: Monad m => Word32 -> Stream m Word8
206word32le = word32leD
208data W64State =
209 W64B1 | W64B2 | W64B3 | W64B4 | W64B5 | W64B6 | W64B7 | W64B8 | W64Done
211-- | Big endian (MSB first) Word64
212{-# INLINE word64beD #-}
213word64beD :: Applicative m => Word64 -> D.Stream m Word8
214word64beD w = D.Stream step W64B1
216 where
218 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
220 step _ W64B1 = yield 56 W64B2
221 step _ W64B2 = yield 48 W64B3
222 step _ W64B3 = yield 40 W64B4
223 step _ W64B4 = yield 32 W64B5
224 step _ W64B5 = yield 24 W64B6
225 step _ W64B6 = yield 16 W64B7
226 step _ W64B7 = yield 8 W64B8
227 step _ W64B8 = pure $ Yield (fromIntegral w :: Word8) W64Done
228 step _ W64Done = pure Stop
230-- | Stream a 'Word64' as eight bytes, the first byte is the MSB of the Word64
231-- and last byte is the LSB (big endian representation).
232--
233-- /Pre-release/
234--
235{-# INLINE word64be #-}
236word64be :: Monad m => Word64 -> Stream m Word8
237word64be = word64beD
239-- | Little endian (LSB first) Word64
240{-# INLINE word64leD #-}
241word64leD :: Applicative m => Word64 -> D.Stream m Word8
242word64leD w = D.Stream step W64B1
244 where
246 yield n s = pure $ Yield (fromIntegral (shiftR w n) :: Word8) s
248 step _ W64B1 = pure $ Yield (fromIntegral w :: Word8) W64B2
249 step _ W64B2 = yield 8 W64B3
250 step _ W64B3 = yield 16 W64B4
251 step _ W64B4 = yield 24 W64B5
252 step _ W64B5 = yield 32 W64B6
253 step _ W64B6 = yield 40 W64B7
254 step _ W64B7 = yield 48 W64B8
255 step _ W64B8 = yield 56 W64Done
256 step _ W64Done = pure Stop
258-- | Stream a 'Word64' as eight bytes, the first byte is the MSB of the Word64
259-- and last byte is the LSB (big endian representation).
260--
261-- /Pre-release/
262--
263{-# INLINE word64le #-}
264word64le :: Monad m => Word64 -> Stream m Word8
265word64le = word64leD
267{-# INLINE int8 #-}
268int8 :: Applicative m => Int8 -> Stream m Word8
269int8 i = word8 (fromIntegral i :: Word8)
271-- | Stream a 'Int16' as two bytes, the first byte is the MSB of the Int16
272-- and second byte is the LSB (big endian representation).
273--
274-- /Pre-release/
275--
276{-# INLINE int16be #-}
277int16be :: Monad m => Int16 -> Stream m Word8
278int16be i = word16be (fromIntegral i :: Word16)
280-- | Stream a 'Int16' as two bytes, the first byte is the LSB of the Int16
281-- and second byte is the MSB (little endian representation).
282--
283-- /Pre-release/
284--
285{-# INLINE int16le #-}
286int16le :: Monad m => Int16 -> Stream m Word8
287int16le i = word16le (fromIntegral i :: Word16)
289-- | Stream a 'Int32' as four bytes, the first byte is the MSB of the Int32
290-- and last byte is the LSB (big endian representation).
291--
292-- /Pre-release/
293--
294{-# INLINE int32be #-}
295int32be :: Monad m => Int32 -> Stream m Word8
296int32be i = word32be (fromIntegral i :: Word32)
298{-# INLINE int32le #-}
299int32le :: Monad m => Int32 -> Stream m Word8
300int32le i = word32le (fromIntegral i :: Word32)
302-- | Stream a 'Int64' as eight bytes, the first byte is the MSB of the Int64
303-- and last byte is the LSB (big endian representation).
304--
305-- /Pre-release/
306--
307{-# INLINE int64be #-}
308int64be :: Monad m => Int64 -> Stream m Word8
309int64be i = word64be (fromIntegral i :: Word64)
311-- | Stream a 'Int64' as eight bytes, the first byte is the LSB of the Int64
312-- and last byte is the MSB (little endian representation).
313--
314-- /Pre-release/
315--
316{-# INLINE int64le #-}
317int64le :: Monad m => Int64 -> Stream m Word8
318int64le i = word64le (fromIntegral i :: Word64)
320-- | Big endian (MSB first) Float
321{-# INLINE float32be #-}
322float32be :: Monad m => Float -> Stream m Word8
323float32be = word32beD . castFloatToWord32
325-- | Little endian (LSB first) Float
326{-# INLINE float32le #-}
327float32le :: Monad m => Float -> Stream m Word8
328float32le = word32leD . castFloatToWord32
330-- | Big endian (MSB first) Double
331{-# INLINE double64be #-}
332double64be :: Monad m => Double -> Stream m Word8
333double64be = word64beD . castDoubleToWord64
335-- | Little endian (LSB first) Double
336{-# INLINE double64le #-}
337double64le :: Monad m => Double -> Stream m Word8
338double64le = word64leD . castDoubleToWord64
340-- | Encode a Unicode character to stream of bytes in 0-255 range.
341--
342{-# INLINE charLatin1 #-}
343charLatin1 :: Applicative m => Char -> Stream m Word8
344charLatin1 = Stream.fromPure . fromIntegral . ord
346{-# INLINE charUtf8 #-}
347charUtf8 :: Monad m => Char -> Stream m Word8
348charUtf8 = Stream.unfold readCharUtf8
350-------------------------------------------------------------------------------
351-- Host byte order
352-------------------------------------------------------------------------------
354-- | Stream a 'Word64' as eight bytes in the host byte order.
355--
356-- /Pre-release/
357--
358{-# INLINE word64host #-}
359word64host :: Monad m => Word64 -> Stream m Word8
360word64host =
361#ifdef WORDS_BIGENDIAN
362 word64be
363#else
364 word64le
365#endif
367-------------------------------------------------------------------------------
368-- Type class
369-------------------------------------------------------------------------------
371class ToBytes a where
372 -- | Convert a Haskell type to a byte stream.
373 toBytes :: a -> Stream m Word8