2-- Module : Streamly.Internal.Data.Binary.Decode
3-- Copyright : (c) 2020 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : pre-release
9-- Parsers for binary encoded basic Haskell data types.
11module Streamly.Internal.Data.Binary.Decode
27import Control.Monad.Catch (MonadCatch, throwM)
28import Control.Monad.IO.Class (MonadIO)
29import Data.Bits ((.|.), unsafeShiftL)
30import Data.Word (Word8, Word16, Word32, Word64)
31import Streamly.Internal.Data.Parser (Parser)
32import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
33import Streamly.Internal.Data.Tuple.Strict (Tuple' (..))
35import qualified Streamly.Internal.Data.Array.Foreign as A
36import qualified Streamly.Internal.Data.Parser as PR
37import qualified Streamly.Internal.Data.Parser.ParserD as PRD
39-- | A value of type '()' is encoded as @0@ in binary encoding.
48unit :: MonadCatch m => Parser m Word8 ()
49unit = eqWord8 0 *> PR.fromPure ()
51{-# INLINE word8ToBool #-}
52word8ToBool :: Word8 -> Either String Bool
53word8ToBool 0 = Right False
54word8ToBool 1 = Right True
55word8ToBool w = Left ("Invalid Bool encoding " ++ Prelude.show w)
57-- | A value of type 'Bool' is encoded as follows in binary encoding.
67bool :: MonadCatch m => Parser m Word8 Bool
68bool = PR.either word8ToBool
70{-# INLINE word8ToOrdering #-}
71word8ToOrdering :: Word8 -> Either String Ordering
72word8ToOrdering 0 = Right LT
73word8ToOrdering 1 = Right EQ
74word8ToOrdering 2 = Right GT
75word8ToOrdering w = Left ("Invalid Ordering encoding " ++ Prelude.show w)
77-- | A value of type 'Ordering' is encoded as follows in binary encoding.
87{-# INLINE ordering #-}
88ordering :: MonadCatch m => Parser m Word8 Ordering
89ordering = PR.either word8ToOrdering
91-- XXX should go in a Word8 parser module?
92-- | Accept the input byte only if it is equal to the specified value.
97eqWord8 :: MonadCatch m => Word8 -> Parser m Word8 Word8
98eqWord8 b = PR.satisfy (== b)
105word8 :: MonadCatch m => Parser m Word8 Word8
106word8 = PR.satisfy (const True)
108-- | Big endian (MSB first) Word16
109{-# INLINE word16beD #-}
110word16beD :: MonadCatch m => PRD.Parser m Word8 Word16
111word16beD = PRD.Parser step initial extract
115 initial = return $ PRD.IPartial Nothing'
118 -- XXX We can use a non-failing parser or a fold so that we do not
119 -- have to buffer for backtracking which is inefficient.
120 return $ PRD.Continue 0 (Just' (fromIntegral a `unsafeShiftL` 8))
122 return $ PRD.Done 0 (w .|. fromIntegral a)
124 extract _ = throwM $ PRD.ParseError "word16be: end of input"
126-- | Parse two bytes as a 'Word16', the first byte is the MSB of the Word16 and
127-- second byte is the LSB (big endian representation).
131{-# INLINE word16be #-}
132word16be :: MonadCatch m => Parser m Word8 Word16
133word16be = PRD.toParserK word16beD
135-- | Little endian (LSB first) Word16
136{-# INLINE word16leD #-}
137word16leD :: MonadCatch m => PRD.Parser m Word8 Word16
138word16leD = PRD.Parser step initial extract
142 initial = return $ PRD.IPartial Nothing'
145 return $ PRD.Continue 0 (Just' (fromIntegral a))
147 return $ PRD.Done 0 (w .|. fromIntegral a `unsafeShiftL` 8)
149 extract _ = throwM $ PRD.ParseError "word16le: end of input"
151-- | Parse two bytes as a 'Word16', the first byte is the LSB of the Word16 and
152-- second byte is the MSB (little endian representation).
156{-# INLINE word16le #-}
157word16le :: MonadCatch m => Parser m Word8 Word16
158word16le = PRD.toParserK word16leD
160-- | Big endian (MSB first) Word32
161{-# INLINE word32beD #-}
162word32beD :: MonadCatch m => PRD.Parser m Word8 Word32
163word32beD = PRD.Parser step initial extract
167 initial = return $ PRD.IPartial $ Tuple' 0 24
169 step (Tuple' w sh) a = return $
172 let w1 = w .|. (fromIntegral a `unsafeShiftL` sh)
173 in PRD.Continue 0 (Tuple' w1 (sh - 8))
174 else PRD.Done 0 (w .|. fromIntegral a)
176 extract _ = throwM $ PRD.ParseError "word32beD: end of input"
178-- | Parse four bytes as a 'Word32', the first byte is the MSB of the Word32
179-- and last byte is the LSB (big endian representation).
183{-# INLINE word32be #-}
184word32be :: MonadCatch m => Parser m Word8 Word32
185word32be = PRD.toParserK word32beD
187-- | Little endian (LSB first) Word32
188{-# INLINE word32leD #-}
189word32leD :: MonadCatch m => PRD.Parser m Word8 Word32
190word32leD = PRD.Parser step initial extract
194 initial = return $ PRD.IPartial $ Tuple' 0 0
196 step (Tuple' w sh) a = return $
197 let w1 = w .|. (fromIntegral a `unsafeShiftL` sh)
199 then PRD.Continue 0 (Tuple' w1 (sh + 8))
202 extract _ = throwM $ PRD.ParseError "word32leD: end of input"
204-- | Parse four bytes as a 'Word32', the first byte is the MSB of the Word32
205-- and last byte is the LSB (big endian representation).
209{-# INLINE word32le #-}
210word32le :: MonadCatch m => Parser m Word8 Word32
211word32le = PRD.toParserK word32leD
213-- | Big endian (MSB first) Word64
214{-# INLINE word64beD #-}
215word64beD :: MonadCatch m => PRD.Parser m Word8 Word64
216word64beD = PRD.Parser step initial extract
220 initial = return $ PRD.IPartial $ Tuple' 0 56
222 step (Tuple' w sh) a = return $
225 let w1 = w .|. (fromIntegral a `unsafeShiftL` sh)
226 in PRD.Continue 0 (Tuple' w1 (sh - 8))
227 else PRD.Done 0 (w .|. fromIntegral a)
229 extract _ = throwM $ PRD.ParseError "word64beD: end of input"
231-- | Parse eight bytes as a 'Word64', the first byte is the MSB of the Word64
232-- and last byte is the LSB (big endian representation).
236{-# INLINE word64be #-}
237word64be :: MonadCatch m => Parser m Word8 Word64
238word64be = PRD.toParserK word64beD
240-- | Little endian (LSB first) Word64
241{-# INLINE word64leD #-}
242word64leD :: MonadCatch m => PRD.Parser m Word8 Word64
243word64leD = PRD.Parser step initial extract
247 initial = return $ PRD.IPartial $ Tuple' 0 0
249 step (Tuple' w sh) a = return $
250 let w1 = w .|. (fromIntegral a `unsafeShiftL` sh)
252 then PRD.Continue 0 (Tuple' w1 (sh + 8))
255 extract _ = throwM $ PRD.ParseError "word64leD: end of input"
257-- | Parse eight bytes as a 'Word64', the first byte is the MSB of the Word64
258-- and last byte is the LSB (big endian representation).
262{-# INLINE word64le #-}
263word64le :: MonadCatch m => Parser m Word8 Word64
264word64le = PRD.toParserK word64leD
266-------------------------------------------------------------------------------
268-------------------------------------------------------------------------------
270-- | Parse eight bytes as a 'Word64' in the host byte order.
274{-# INLINE word64host #-}
275word64host :: (MonadIO m, MonadCatch m) => Parser m Word8 Word64
277 fmap (A.unsafeIndex 0 . A.castUnsafe) $ PR.takeEQ 8 (A.writeN 8)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list