class Erlang::Bitstring

A `Bitstring` is a series of bits.

### Creating Bitstrings

Erlang::Bitstirng["test", bits: 7]
# => Erlang::Bitstring[116, 101, 115, 4, bits: 3]

Constants

BIT_PACK

@private

Attributes

bits[R]

Return the bits for this `Bitstring` @return [::Integer]

data[R]

Return the data for this `Bitstring` @return [::String]

Public Class Methods

[](*data, bits: 8) click to toggle source

Create a new `Bitstring` populated with the given `data` and `bits`. @param data [::String, Symbol, ::Enumerable, Integer] The content of the `Binary` @param bits [Integer] The number of bits to keep on the last byte @return [Bitstring, Binary] @raise [ArgumentError] if `data` cannot be coerced to be a `::String` or `bits` is not between 1 and 8

# File lib/erlang/bitstring.rb, line 27
def [](*data, bits: 8)
  return EmptyBinary if data.empty?
  raise ArgumentError, 'bits must be an Integer' if not bits.is_a?(::Integer)
  raise ArgumentError, 'bits must be between 1 and 8' if bits < 1 or bits > 8
  binary = Erlang.iolist_to_binary(data)
  if bits == 8 or binary.empty?
    return binary
  else
    return new(binary, bits)
  end
end
compare(a, b) click to toggle source

Compares `a` and `b` and returns whether they are less than, equal to, or greater than each other.

@param a [Bitstring, Binary] The left argument @param b [Bitstring, Binary] The right argument @return [-1, 0, 1] @raise [ArgumentError] if `a` or `b` is not a `Bitstring` or `Binary`

# File lib/erlang/bitstring.rb, line 50
def compare(a, b)
  raise ArgumentError, "'a' must be of Erlang::Binary or Erlang::Bitstring type" if not a.kind_of?(Erlang::Binary) and not a.kind_of?(Erlang::Bitstring)
  raise ArgumentError, "'b' must be of Erlang::Binary or Erlang::Bitstring type" if not b.kind_of?(Erlang::Binary) and not b.kind_of?(Erlang::Bitstring)
  c = a.bitsize <=> b.bitsize
  return a.data <=> b.data if c == 0
  c = 0
  i = 0
  abytes = a.bytesize
  bbytes = b.bytesize
  abytes -= 1 if a.bits != 8
  bbytes -= 1 if b.bits != 8
  while c == 0 and i < abytes and i < bbytes
    c = a.data.getbyte(i) <=> b.data.getbyte(i)
    i += 1
  end
  if c == 0
    if (a.bits != 8 and i == abytes and i < bbytes) or (b.bits != 8 and i == bbytes and i < abytes) or (a.bits != 8 and b.bits != 8)
      abyte = a.data.getbyte(i)
      bbyte = b.data.getbyte(i)
      askip = 8 - a.bits
      bskip = 8 - b.bits
      i = 0
      loop do
        if i == a.bits and i == b.bits
          c = 0
          break
        elsif i == a.bits
          c = -1
          break
        elsif i == b.bits
          c = 1
          break
        end
        abit = (abyte >> (7 - ((i + askip) & 7))) & 1
        bbit = (bbyte >> (7 - ((i + bskip) & 7))) & 1
        c = abit <=> bbit
        break if c != 0
        i += 1
        break if (i & 7) == 0
      end
    elsif i >= a.bytesize and i < b.bytesize
      c = -1
    elsif i >= b.bytesize and i < a.bytesize
      c = 1
    end
  end
  return c
end
concat(*iodata) click to toggle source

Concatenates list of `Binary` or `Bitstring` items into a single `Binary` or `Bitstring`.

@example

Erlang::Bitstring.concat(Erlang::Bitstring[1, bits: 2], Erlang::Binary[255])
# => Erlang::Bitstring[127, 3, bits: 2]

@param iodata [Binary, Bitstring] The list of bitstrings @return [Binary, Bitstring]

# File lib/erlang/bitstring.rb, line 107
def concat(*iodata)
  return iodata.reduce(Erlang::EmptyBinary) { |acc, item| acc.concat(item) }
end
empty() click to toggle source
# File lib/erlang/bitstring.rb, line 39
def empty
  return Erlang::EmptyBinary
end
new(data = nil, bits = 8) click to toggle source

@private

# File lib/erlang/bitstring.rb, line 113
def initialize(data = nil, bits = 8)
  raise ArgumentError, 'bits must be an Integer' if not bits.is_a?(::Integer)
  raise ArgumentError, 'bits must be between 1 and 8' if bits < 1 or bits > 8
  data = ::String.new if data.nil?
  data = data.data if data.is_a?(Erlang::Binary)
  raise ArgumentError, 'data must be a String' if not data.is_a?(::String)
  data = Erlang::Terms.binary_encoding(data)
  if data.bytesize > 0
    data.setbyte(-1, ((data.getbyte(-1) << (8 - bits)) & 255) >> (8 - bits))
  end
  @data = data.freeze
  @bits = bits.freeze
  @bitsize = (@data.bytesize == 0) ? 0 : (((@data.bytesize - 1) * 8) + @bits)
end

Public Instance Methods

+(*other)
Alias for: concat
==(other)
Alias for: eql?
[](position)
Alias for: at
at(position) click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 135
def at(position)
  raise NotImplementedError
end
Also aliased as: []
bitsize() click to toggle source

@return [Integer] the number of bits in this `Bitstring`

# File lib/erlang/bitstring.rb, line 141
def bitsize
  return @bitsize
end
bitslice(arg, length = (missing_length = true)) click to toggle source

Return specific objects from the `Bitstring`. All overloads return `nil` if the starting index is out of range.

@overload bitslice(index)

Returns a single bit at the given `index`. If `index` is negative,
count backwards from the end.

@param index [Integer] The index to retrieve. May be negative.
@return [Integer, nil]
@example
  b = Erlang::Bitstring[2, bits: 2]
  b.bitslice(0)  # => 1
  b.bitslice(1)  # => 0
  b.bitslice(-1) # => 0
  b.bitslice(2)  # => nil

@overload bitslice(index, length)

Return a bitstring starting at `index` and continuing for `length`
bits or until the end of the `Bitstring`, whichever occurs first.

@param start [Integer] The index to start retrieving bits from. May be
                       negative.
@param length [Integer] The number of bits to retrieve.
@return [Bitstring, Binary]
@example
  b = Erlang::Bitstring[1, 117, bits: 7]
  b.bitslice(0, 11) # => Erlang::Bitstring[1, 7, bits: 3]
  b.bitslice(11, 4) # => Erlang::Bitstring[5, bits: 4]
  b.bitslice(16, 1) # => nil

@overload bitslice(index..end)

Return a bitstring starting at `index` and continuing to index
`end` or the end of the `Bitstring`, whichever occurs first.

@param range [Range] The range of bits to retrieve.
@return [Bitstring, Binary]
@example
  b = Erlang::Bitstring[1, 117, bits: 7]
  b.bitslice(0...11)  # => Erlang::Bitstring[1, 7, bits: 3]
  b.bitslice(11...15) # => Erlang::Bitstring[5, bits: 4]
  b.bitslice(16..-1)  # => nil

@see Erlang::Binary#bitslice

# File lib/erlang/bitstring.rb, line 191
def bitslice(arg, length = (missing_length = true))
  if missing_length
    if arg.is_a?(Range)
      from, to = arg.begin, arg.end
      from += bitsize if from < 0
      return nil if from < 0
      to   += bitsize if to < 0
      to   += 1       if !arg.exclude_end?
      length = to - from
      length = 0 if length < 0
      length = bitsize - from if (from + length) > bitsize
      return nil if length < 0
      l8 = length.div(8)
      l1 = length % 8
      pad = 8 - l1
      enum = each_bit
      skip = from
      enum = enum.drop_while {
        if skip > 0
          skip -= 1
          next true
        else
          next false
        end
      }
      head = enum.take(length)
      if l1 == 0
        return Erlang::Binary[[head.join].pack(BIT_PACK)]
      else
        tail = head[-l1..-1]
        head = head[0...-l1]
        tail = ([0] * pad).concat(tail)
        return Erlang::Bitstring[[[head.join, tail.join].join].pack(BIT_PACK), bits: l1]
      end
    else
      arg += bitsize if arg < 0
      return nil if arg < 0
      return nil if arg >= bitsize
      a8 = arg.div(8)
      a1 = arg % 8
      byte = @data.getbyte(a8)
      return nil if byte.nil?
      return (byte >> ((@bits - a1 - 1) & 7)) & 1
    end
  else
    return nil if length < 0
    arg += bitsize if arg < 0
    return nil if arg < 0
    length = bitsize - arg if (arg + length) > bitsize
    return nil if length < 0
    l8 = length.div(8)
    l1 = length % 8
    pad = 8 - l1
    enum = each_bit
    skip = arg
    enum = enum.drop_while {
      if skip > 0
        skip -= 1
        next true
      else
        next false
      end
    }
    head = enum.take(length)
    if l1 == 0
      return Erlang::Binary[[head.join].pack(BIT_PACK)]
    else
      tail = head[-l1..-1]
      head = head[0...-l1]
      tail = ([0] * pad).concat(tail)
      return Erlang::Bitstring[[[head.join, tail.join].join].pack(BIT_PACK), bits: l1]
    end
  end
end
bytesize() click to toggle source

@return [Integer] the number of bytes in this `Bitstring`

# File lib/erlang/bitstring.rb, line 267
def bytesize
  return @data.bytesize
end
Also aliased as: size
concat(*other) click to toggle source

Concatenates list of `Binary` or `Bitstring` items into a single `Binary` or `Bitstring`.

@example

Erlang::Bitstring[3, bits: 3].concat(Erlang::Bitstring[1, bits: 5])
# => "a"

@param iodata [Binary, Bitstring] The list of bitstrings @return [Binary, Bitstring]

# File lib/erlang/bitstring.rb, line 280
def concat(*other)
  if other.size == 1 and (other[0].kind_of?(Erlang::Binary) or other[0].kind_of?(Erlang::Bitstring))
    other = other[0]
  else
    other = Erlang::Binary[*other]
  end
  return other if empty?
  return self if other.empty?
  if @bits == 8
    return to_binary.concat(other)
  else
    bits = (@bits + other.bits) % 8
    head = [*each_bit, *other.each_bit]
    if bits == 0
      return Erlang::Binary[[head.join].pack(BIT_PACK)]
    else
      pad  = 8 - bits
      tail = head[-bits..-1]
      head = head[0...-bits]
      tail = ([0] * pad).concat(tail)
      return Erlang::Bitstring[[[head.join, tail.join].join].pack(BIT_PACK), bits: bits]
    end
  end
end
Also aliased as: +
copy(n = 1) click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 307
def copy(n = 1)
  raise NotImplementedError
end
decode_unsigned(endianness = :big) click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 312
def decode_unsigned(endianness = :big)
  raise NotImplementedError
end
each_bit() { |bit| ... } click to toggle source

Call the given block once for each bit in the `Bitstring`, passing each bit from first to last successively to the block. If no block is given, returns an `Enumerator`.

@return [self] @yield [Integer]

# File lib/erlang/bitstring.rb, line 322
def each_bit
  return enum_for(:each_bit) unless block_given?
  index = 0
  headbits = (self.bytesize - 1) * 8
  skipbits = 8 - @bits
  @data.each_byte do |byte|
    loop do
      break if index == @bitsize
      if index >= headbits
        bit = (byte >> (7 - ((index + skipbits) & 7))) & 1
      else
        bit = (byte >> (7 - (index & 7))) & 1
      end
      yield bit
      index += 1
      break if (index & 7) == 0
    end
  end
  return self
end
each_bitslice(number) { |bitslice(index * number, number)| ... } click to toggle source

Split the bits in this `Bitstring` in groups of `number` bits, and yield each group to the block (as a `List`). If no block is given, returns an `Enumerator`.

@example

b = Erlang::Bitstring[117, bits: 7]
b.each_bitslice(4).to_a # => [Erlang::Bitstring[14, bits: 4], Erlang::Bitstring[5, bits: 3]]

@return [self, Enumerator] @yield [Binary, Bitstring] Once for each bitstring. @see Erlang::Bitstring#each_bitslice

# File lib/erlang/bitstring.rb, line 354
def each_bitslice(number)
  return enum_for(:each_bitslice, number) unless block_given?
  raise ArgumentError, 'number must be a positive Integer' if not number.is_a?(::Integer) or number < 1
  slices = bitsize.div(number) + ((bitsize % number == 0) ? 0 : 1)
  index  = 0
  loop do
    break if slices == 0
    yield(bitslice(index * number, number))
    slices -= 1
    index  += 1
  end
  return self
end
each_byte() click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 369
def each_byte
  raise NotImplementedError
end
empty?() click to toggle source

Returns true if this `Bitstring` is empty.

@return [Boolean]

# File lib/erlang/bitstring.rb, line 376
def empty?
  return @data.empty?
end
eql?(other) click to toggle source

Return true if `other` has the same type and contents as this `Bitstring`.

@param other [Object] The object to compare with @return [Boolean]

# File lib/erlang/bitstring.rb, line 384
def eql?(other)
  return true if other.equal?(self)
  if instance_of?(other.class)
    return !!(self.class.compare(self, other) == 0)
  else
    return !!(Erlang.compare(other, self) == 0)
  end
end
Also aliased as: ==
erlang_inspect(raw = false) click to toggle source

Return the contents of this `Bitstring` as a Erlang-readable `::String`.

@example

Erlang::Bitstring["test", bits: 3].erlang_inspect
# => "<<116,101,115,4:3>>"

@return [::String]

# File lib/erlang/bitstring.rb, line 416
def erlang_inspect(raw = false)
  return Erlang.inspect(Erlang::Binary.new(@data), raw: raw) if @bits == 8
  result = '<<'
  bytes = @data.bytes
  if last = bytes.pop
    result << bytes.join(',')
    result << ',' if not bytes.empty?
    if @bits == 8
      result << "#{last}"
    else
      result << "#{last}:#{@bits}"
    end
  end
  result << '>>'
  return result
end
first() click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 395
def first
  raise NotImplementedError
end
hash() click to toggle source

@private

# File lib/erlang/bitstring.rb, line 129
def hash
  hash = @data.hash
  return (hash << 5) - hash + bits.hash
end
inspect() click to toggle source

@return [::String] the nicely formatted version of the `Bitstring`

# File lib/erlang/bitstring.rb, line 434
def inspect
  return "Erlang::Bitstring[#{data.bytes.inspect[1..-2]}, bits: #{bits.inspect}]"
end
last() click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 400
def last
  raise NotImplementedError
end
marshal_dump() click to toggle source

@return [::String] @private

# File lib/erlang/bitstring.rb, line 452
def marshal_dump
  return [@data, @bits]
end
marshal_load(args) click to toggle source

@private

# File lib/erlang/bitstring.rb, line 457
def marshal_load(args)
  data, bits = args
  initialize(data, bits)
  __send__(:immutable!)
  return self
end
part(position, length) click to toggle source

@raise [NotImplementedError]

# File lib/erlang/bitstring.rb, line 405
def part(position, length)
  raise NotImplementedError
end
size()
Alias for: bytesize
to_binary() click to toggle source

@return [Binary] the `Binary` version of the `Bitstring` padded with zeroes

# File lib/erlang/bitstring.rb, line 439
def to_binary
  return EmptyBinary if empty?
  return Erlang::Binary[@data]
end
to_s() click to toggle source

@return [::String] the string version of the `Bitstring`

# File lib/erlang/bitstring.rb, line 445
def to_s
  return @data
end
Also aliased as: to_str
to_str()
Alias for: to_s