on master help sign in
airlock/src/BitParser.elm
148 lines 3.3 kB history raw
1module BitParser exposing
2 ( BitParser
3 , andThen
4 , bit
5 , bits
6 , bitsToInt
7 , fail
8 , getOffset
9 , intBits
10 , map
11 , rawBits
12 , run
13 , succeed
14 )
16import Bitwise
17import Bytes exposing (Bytes)
18import Bytes.Decode as BD
19import Bytes.Encode as BE
22run : BitParser a -> Bytes -> Maybe a
23run (BitParser f) bytes =
24 BD.decode (f { running = Nothing, offset = 0 }) bytes |> Maybe.map Tuple.second
27type alias BitParserState =
28 { running : Maybe { byte : Int, length : Int }
29 , offset : Int
30 }
33type BitParser a
34 = BitParser (BitParserState -> BD.Decoder ( BitParserState, a ))
37getOffset : BitParser Int
38getOffset =
39 BitParser (\state -> BD.succeed ( state, state.offset ))
42bit : BitParser Int
43bit =
44 BitParser
45 (\{ running, offset } ->
46 let
47 newOffset =
48 offset + 1
49 in
50 case running of
51 Nothing ->
52 BD.unsignedInt8
53 |> BD.map
54 (\i ->
55 ( { running = Just { byte = Bitwise.shiftRightBy 1 i, length = 7 }
56 , offset = newOffset
57 }
58 , Bitwise.and 1 i
59 )
60 )
62 Just { byte, length } ->
63 BD.succeed
64 (if length == 1 then
65 ( { running = Nothing, offset = newOffset }, byte )
67 else
68 ( { running = Just { byte = Bitwise.shiftRightBy 1 byte, length = length - 1 }
69 , offset = newOffset
70 }
71 , Bitwise.and 1 byte
72 )
73 )
74 )
77rawBits : Int -> BitParser (List Int)
78rawBits n =
79 let
80 go i =
81 if i <= 0 then
82 succeed []
84 else
85 bit |> andThen (\b -> map (\x -> b :: x) (go (i - 1)))
86 in
87 go n
91-- PERF: use `bytes` on byte boundaries
94bits : Int -> BitParser Bytes
95bits n =
96 rawBits n |> map bitsToBytes
99intBits : Int -> BitParser Int
100intBits n =
101 rawBits n |> map bitsToInt
104bitsToInt : List Int -> Int
105bitsToInt =
106 List.foldr (\b acc -> Bitwise.shiftLeftBy 1 acc |> Bitwise.or b) 0
109bitsToBytes : List Int -> Bytes
110bitsToBytes bs =
111 if bs == [] then
112 emptyBytes
114 else
115 let
116 go bb =
117 if List.length bb > 8 then
118 BE.unsignedInt8 (List.take 8 bb |> bitsToInt) :: go (List.drop 8 bb)
120 else
121 [ BE.unsignedInt8 (bb |> bitsToInt) ]
122 in
123 go bs |> BE.sequence |> BE.encode
126emptyBytes : Bytes
127emptyBytes =
128 BE.encode (BE.sequence [])
131andThen : (a -> BitParser b) -> BitParser a -> BitParser b
132andThen f (BitParser g) =
133 BitParser (\s -> g s |> BD.andThen (\( s1, a ) -> f a |> (\(BitParser h) -> h s1)))
136map : (a -> b) -> BitParser a -> BitParser b
137map f (BitParser g) =
138 BitParser (\s -> g s |> BD.map (Tuple.mapSecond f))
141succeed : a -> BitParser a
142succeed a =
143 BitParser (\state -> BD.succeed ( state, a ))
146fail : BitParser a
147fail =
148 BitParser (always BD.fail)