I'm reading a binary file, and within it there is a structure where the first byte of data indicates the type of data following it. I'm trying to handle this via pattern matching, and am having trouble.
I've tried a few ways I figured may work, none of which do. You can see my feeble attempts below:
defmodule Test do
def build(<< 0x11, rest >>) do
"11!"
end
def build(<< 0x12, rest :: size(4) >>) do
"12!"
end
def build(<< type, rest >>)
when type == 0x13 do
"13!"
end
def build(bytes) do
"Unknown!"
end
end
[ << 0x11, 0x01, 0x02, 0x03, 0x04 >>,
<< 0x12, 0x01, 0x02, 0x03, 0x04 >>,
<< 0x13, 0x01, 0x02, 0x03, 0x04 >> ]
|> Enum.map(&Test.build/1)
|> IO.inspect
# => ["Unknown!", "Unknown!", "Unknown!"]
I'd like to get: ["11!", "12!", "13!"]
instead.
The data matched by these is all a fixed size (in this case 5 total bytes). This SO question seems to suggest I need to specify the total size as well? Not sure how to do that.
Ultimately I don't care about the value of the first byte if the methods are dispatched via matching, so rest
is the only thing I really need within each method body. What am I missing?
Each unbound variable in a binary pattern matches one byte by default. If you want to match an arbitrary length rest, you need to use the binary
modifier.
defmodule Test do
def build(<<0x11, rest :: binary>>) do
"11!"
end
def build(<<0x12, rest :: binary>>) do
"12!"
end
def build(<<0x13, rest :: binary>>) do
"13!"
end
def build(bytes) do
"Unknown!"
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With