As you know, Erlang and Elixir have a good specifications/functions for binary. However, I haven’t found it for bitstring. Here is some examples I ran into. I’m happy to hear your thoughts and solutions. Please let me know
Making a value
Sometimes you desire making a value as you read such as “00010010_10101011”.
It’s easy for binary with using integer literal starting 0b
and :binary.encode_unsigned/1
.
iex(1)> a = 0b00010010_10101011
4779
iex(2)> b = :binary.encode_unsigned(a)
<<18, 171>>
iex(3)> bit_size(b)
16
iex(4)> i b
Term
<<18, 171>>
Data type
BitString
Byte size
2
Description
This is a binary: a collection of bytes. It's printed with the `<<>>`
syntax (as opposed to double quotes) because it is not a UTF-8 encoded
binary (the first invalid byte being `<<171>>`)
Reference modules
:binary
Implemented protocols
Collectable, IEx.Info, Inspect, List.Chars, String.Chars
However, :binary.encode_unsigned/1
always makes a binary, I haven’t found the best practice for making a bitstring. Here is some techniques I use currently:
iex(1)> <<0::1, 1::1, 0::1, 1::1, 1::1>>
<<11::size(5)>>
iex(2)> # It's a little bit verbose but It works well
nil
iex(3)> <<0b01011::5>>
<<11::size(5)>
iex(4)> # It's simple but requires size explicitly
nil
and also using sigil which I have implemented.
iex(7)> import BitsSigils
BitsSigils
iex(8)> ~b(01011)
<<11::size(5)>>
iex(9)> # I like this, but needs to implement some codes
nil
Concatinating
For binary, We use <>/2
to concatinate.
iex(1)> a = "abc"
"abc"
iex(2)> b = "123"
"123"
iex(3)> a <> b
"abc123"
For bitstring, I can’t use both <>/2
and just <<>>/2
.
iex(1)> a = <<1::1>>
<<1::size(1)>>
iex(2)> b = <<0::1>>
<<0::size(1)>>
iex(3)> a <> b
** (ArgumentError) argument error
(stdlib) eval_bits.erl:101: :eval_bits.eval_exp_field1/6
(stdlib) eval_bits.erl:92: :eval_bits.eval_field/3
(stdlib) eval_bits.erl:68: :eval_bits.expr_grp/4
(stdlib) erl_eval.erl:484: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3
iex(3)> <<a, b>>
** (ArgumentError) argument error
(stdlib) eval_bits.erl:101: :eval_bits.eval_exp_field1/6
(stdlib) eval_bits.erl:92: :eval_bits.eval_field/3
(stdlib) eval_bits.erl:68: :eval_bits.expr_grp/4
(stdlib) erl_eval.erl:484: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/
So, I use <<>>/2
with segment types( ::bitstring
).
iex(3)> <<a::bitstring, b::bitstring>>
<<2::size(2)>>
Converting into integer
For binary, we have nice functions thanks for :binary
module. Unfortunary, It doesn’t work for bitstring.
iex(1)> :binary.decode_unsigned(<<1, 255>>)
511
iex(2)> :binary.decode_unsigned(<<1::1, 255>>)
** (ArgumentError) argument error
(stdlib) :binary.decode_unsigned(<<255, 1::size(1)>>)
I use pattern matching converting bitstring to integer. Please note you can only use integer or variable for size of bitstring in <<>>/2
.
iex(1)> a = <<1::1, 255>>
<<255, 1::size(1)>>
iex(2)> <<x::integer-size(bit_size(a))>> = a
** (CompileError) iex:2: size in bitstring expects an integer or a variable as argument, got: :erlang.bit_size(a)
(elixir) src/elixir_bitstring.erl:197: :elixir_bitstring.expand_each_spec/5
(elixir) src/elixir_bitstring.erl:168: :elixir_bitstring.expand_specs/6
(elixir) src/elixir_bitstring.erl:41: :elixir_bitstring.expand/8
(elixir) src/elixir_bitstring.erl:10: :elixir_bitstring.expand/4
iex(2)> b = bit_size(a)
9
iex(3)> <<x::integer-size(b)>> = a
<<255, 1::size(1)>>
iex(4)> x
511