edmz

View on GitHub

Pattern Matching and Bitstring Syntax in Elixir

While coding a simple decoder, I had the need to parse a stream of bytes and then sort them in reverse order.

The stream has following form:

COUNT BYTE1 BYTE2 BYTE3 ... REST

Where COUNT specifies the number of BYTEs to read after count.

Assuming a value of 3 for COUNT, the expected result of the algorithm should be:

BYTE3 BYTE2 BYTE1

This is kind of trivial, but I wanted to do it in an idiomatic way.

After asking around for suggestions in #elixir-lang, @nox suggested the following code

binary_string = <<3, 10, 20, 30>>
<<num_bytes::8, int::size(num_bytes)-unit(8), rest::binary>> = binary_string
<<int::little-size(num_bytes)-unit(8)>>
# result would be <<30, 20, 10>>

This is a clever solution and it showcases pattern matching as well as the binary parsing syntax.

For those not familiar with elixir, here is a rundown of what happens:

# this is sample data. A sample list of bytes, with the specified values
binary_string = <<3, 10, 20, 30, 40, 50>>

# using pattern matching and binary syntax, we are telling elixir to
# 'assign' the first 8 bits to `num_bytes`, then the next `num_bytes` bytes
# in a variable called int. The rest can be safely ignored.
<<num_bytes::8, int::size(num_bytes)-unit(8), _::binary>> = binary_string

# Then, we build another `array` of bytes wht the value of `int`. But since
# specify the endianness, the will be automatically sorted in the revers order.
<<int::little-size(num_bytes)-unit(8)>>
# result would be <<30, 20, 10>>

Quite clever and concise if you ask me.