Hey, I'm working on parsing a binary format in Roc and I need to parse a series of bytes into an integer. To be specific, I need to parse a little endian u64. Is there a builtin for this?
Hi @Louis Pearson,
There used to be builtins for this but they got removed. I believe because they detected endianness automatically and we did not want the same pure roc program to return different outputs on different devices.
Ok, that makes sense. I decided to write my own function for it:
leBytesToU64 : List U8 -> U64
leBytesToU64 = \bytes ->
expect List.len bytes == 8
.value (List.walk bytes {value: 0, index: 0} \{value, index}, byte ->
{ value: value + (Num.shiftRightBy (Num.toU64 byte) (index * 4))
, index: index + 1
})
It's important to be aware that inline expect statements are discarded when building a roc program for release (with roc build
). So you probably want to use Result
here, or if you're building something quick and dirty you can use the crash
keyword.
Thank you! Took me a little bit to work out how to integrate it into the rest of my code, but I've changed the function to look like this:
leBytesToU64 : List U8 -> Result U64 [WrongListLength]
leBytesToU64 = \bytes ->
if List.len bytes == 8 then
Ok (.value (List.walk bytes {value: 0, index: 0} \{value, index}, byte ->
{ value: value + (Num.shiftRightBy (Num.toU64 byte) (index * 4))
, index: index + 1
}))
else
Err WrongListLength
My main problem was trying to do everything in one function chaining a bunch of Task.await calls. I fixed it by moving the functional code to it's own function that returns a result and then convert that to Task.Ok/Task.Err based on the result
Using dbg for my print statements also helped
We have a solid design for this, just needs someone to implement I think. It's been a while since I looked at this, but I dont think we made a tracking issue for it yet. Here's the discussion https://roc.zulipchat.com/#narrow/stream/383402-API-Design/topic/reading.20integers.20from.20bytes/near/418550042
I think the final design is to leave it to users for integers
I think it is just fractional types that will require methods to break them into pieces
this is a great approach @Louis Pearson! :smiley:
I wonder if llvm will inline that all happily to get the optimized output.
If not, probably have to do it the more manual way:
leBytesToU64 : List U8 -> Result U64 [WrongListLength]
leBytesToU64 = \bytes ->
when bytes is
[b0, b1, b2, b3, b4, b5, b6, b7] ->
Num.toU64 b0
|> Num.bitwiseOr (Num.toU64 b1 |> Num.shiftLeftBy 8)
|> Num.bitwiseOr (Num.toU64 b2 |> Num.shiftLeftBy 16)
|> Num.bitwiseOr (Num.toU64 b3 |> Num.shiftLeftBy 24)
|> Num.bitwiseOr (Num.toU64 b4 |> Num.shiftLeftBy 32)
|> Num.bitwiseOr (Num.toU64 b5 |> Num.shiftLeftBy 40)
|> Num.bitwiseOr (Num.toU64 b6 |> Num.shiftLeftBy 48)
|> Num.bitwiseOr (Num.toU64 b7 |> Num.shiftLeftBy 56)
_ ->
Err NotEnoughData
Oh, also, in your example, you probably want to use List.walkWithIndex. Something like this is a bit more cleaned up:
leBytesToU64 : List U8 -> Result U64 [WrongListLength]
leBytesToU64 = \bytes ->
if List.len bytes == 8 then
List.walkWithIndex bytes 0 \value, byte, index ->
value + (Num.shiftRightBy (Num.toU64 byte) (index * 4))
|> Ok
else
Err WrongListLength
Hmm, just realized my implementation is multiplying index by 4 when it should be multiplying by 8
Thanks for the examples BTW, still trying to get my bearings in Roc
I'm more used to procedural languages like zig
Yeah, definitely is a learning curve. Roc was my first langauge where I really dove more into FP.
Like I have done some elm, ocaml, and haskel, but not enough to actually feel like I know FP. Just basic tutorial level stuff.
Yeah, I'm in the same boat
I found elm to be a really compelling language when I first encountered it, but I don't do that much frontend web development so I didn't have a use case for it. I know Roc is still early days but I'm excited by the idea of it
yeah, same here. Elm has been in my back pocket but I essentially never do web dev.
@Louis Pearson would you be interested in making a library/package that implements the Decoding
and Encoding
abilities like JSON does? If so I could help you with that. It's been on my list for a couple of months now but I haven't quite got around to it. We don't quite have all the pieces like for Dec/Frac etc, but I guess we could leave them unimplemented for now.
Also, I'm interested to know what binary format you are looking at. It sounds interesting
Sure, is there a guide to creating a Roc package?
The binary format is the signature block in Android APKs
I don't think we have a guide yet
https://source.android.com/docs/security/features/apksigning/v2
I don't think this is a candidate for decode and encode. It is a specific binary header rather than a generic binary format
I thought the question of packaging was for encode/decode of little-endian or big-endian integers, not for APK signing
Ah fair, though either way, it can't use the actual Encoding
and Decoding
abilities unless it is a full generic binary serialization format.
Last updated: Jul 05 2025 at 12:14 UTC