Helpers for working with Bytes.Decoders.
Before the release of [elm/bytes], many packages would use List Int
to represent bytes. byteValues aids interaciton between those packages
and Bytes.
import Hex
import Bytes exposing (Bytes)
import Bytes.Decode exposing (Decoder)
import Bytes.Extra exposing (fromByteValues)
input : Bytes
input = fromByteValues [ 0x32, 0xff, 0x53 ]
decoder : Decoder (List String)
decoder =
byteValues (Bytes.width input)
|> Bytes.Decode.map (List.map Hex.toString)
Bytes.Decode.decode decoder input
--> Just [ "32", "ff", "53" ]Json.Decode.Pipeline provides a neat, scalable way for
decoding JSON. This module provides a few helpers for adopting a similar style
when decoding Bytes.
It is important to note that decoding bytes poses more restrictions than
decoding JSON, as bytes are consumed in order, and a maximum of one time. This
makes an equivalent to Json.Decode.Pipeline.optional difficult to impossible.
import Bytes exposing (Endianness(..))
import Bytes.Decode exposing (Decoder, succeed, andThen, unsignedInt32, string, float64, decode)
import Bytes.Extra exposing (fromByteValues)
type Status = Downloaded | LocallyGenerated
type alias MyData =
{ id: Int
, status : Status
, name: String
, value: Float
}
myDataDecoder : Decoder MyData
myDataDecoder =
succeed MyData
|> andMap (unsignedInt32 BE)
|> hardcoded Downloaded
|> andMap (unsignedInt32 BE |> andThen string)
|> andMap (float64 BE)
decode myDataDecoder (fromByteValues [0,0,0,252,0,0,0,8,116,104,101,95,110,97,109,101,63,224,0,0,0,0,0,0])
--> Just
--> { id = 252
--> , status = Downloaded
--> , name = "the_name"
--> , value = 0.5
--> }andMap behaves in a similar way to Json.Decode.Pipeline.required. It is named andMap to match the naming of similar functions in other packages, and because this package does not provide an equivalent to Json.Decode.Pipeline.optional.
modelDecoder : Decoder Model
modelDecoder =
succeed Model
|> andMap (unsignedInt32 BE)
|> andMap (unsignedInt32 BE |> andThen string)
|> andMap myCustomTypeDecoder
|> andMap myCustomBooleanDecoderA neat way to fill in predetermined information that's not part of the data
being decoded, similar to Json.Decode.Pipeline.hardcoded.
modelDecoder : Decoder Model
modelDecoder =
succeed Model
|> andMap (unsignedInt32 BE)
|> andMap (unsignedInt32 BE |> andThen string)
|> hardcoded []
|> andMap myCustomBooleanDecoder
|> hardcoded SubModel.defaultTake a Decoder (Result err a) and make it fail if it decodes an Err.
Take a Decoder (Maybe a) and make it fail if it decodes to Nothing.
import Bytes.Extra exposing (fromByteValues)
import Bytes.Decode exposing (..)
maybeBoolDecoder : Decoder (Maybe Bool)
maybeBoolDecoder =
Bytes.Decode.map
(\int ->
case int of
0 -> Just False
1 -> Just True
_ -> Nothing
)
Bytes.Decode.unsignedInt8
boolDecoder : Decoder Bool
boolDecoder =
onlyJusts maybeBoolDecoder
decode maybeBoolDecoder (fromByteValues [0x01])
--> Just (Just True)
decode boolDecoder (fromByteValues [0x01])
--> Just True
Run a decoder a set amount of times, and collect the result in a list.