module Erlang

Erlang term classes listed alphabetically

Constants

TAG_ATOM_CACHE_REF
TAG_ATOM_EXT
TAG_ATOM_UTF8_EXT
TAG_BINARY_EXT
TAG_BIT_BINARY_EXT
TAG_COMPRESSED_ZLIB
TAG_EXPORT_EXT
TAG_FLOAT_EXT
TAG_FUN_EXT
TAG_INTEGER_EXT
TAG_LARGE_BIG_EXT
TAG_LARGE_TUPLE_EXT
TAG_LIST_EXT
TAG_LOCAL_EXT
TAG_MAP_EXT
TAG_NEWER_REFERENCE_EXT
TAG_NEW_FLOAT_EXT
TAG_NEW_FUN_EXT
TAG_NEW_PID_EXT
TAG_NEW_PORT_EXT
TAG_NEW_REFERENCE_EXT
TAG_NIL_EXT
TAG_PID_EXT
TAG_PORT_EXT
TAG_REFERENCE_EXT
TAG_SMALL_ATOM_EXT
TAG_SMALL_ATOM_UTF8_EXT
TAG_SMALL_BIG_EXT
TAG_SMALL_INTEGER_EXT
TAG_SMALL_TUPLE_EXT
TAG_STRING_EXT
TAG_V4_PORT_EXT
TAG_VERSION

tag values here www.erlang.org/doc/apps/erts/erl_ext_dist.html

Public Class Methods

binary_to_term(data) click to toggle source

core functionality

# File lib/erlang.rb, line 308
def self.binary_to_term(data)
    size = data.bytesize
    if size <= 1
        raise ParseException, 'null input', caller
    end
    if data[0].ord != TAG_VERSION
        raise ParseException, 'invalid version', caller
    end
    begin
        result = binary_to_term_(1, data)
        if result[0] != size
            raise ParseException, 'unparsed data', caller
        end
        return result[1]
    rescue NoMethodError => e
        raise ParseException, 'missing data', e.backtrace
    rescue TypeError => e
        raise ParseException, 'missing data', e.backtrace
    rescue ArgumentError => e
        raise ParseException, 'missing data', e.backtrace
    end
end
set_undefined(value) click to toggle source

Elixir use can set to ‘nil’

# File lib/erlang.rb, line 355
def self.set_undefined(value)
    @@UNDEFINED = value
end
term_to_binary(term, compressed = false) click to toggle source
# File lib/erlang.rb, line 331
def self.term_to_binary(term, compressed = false)
    data_uncompressed = term_to_binary_(term)
    if compressed == false
        return "#{TAG_VERSION.chr}#{data_uncompressed}"
    else
        if compressed == true
            compressed = 6
        end
        if compressed < 0 or compressed > 9
            raise InputException, 'compressed in [0..9]', caller
        end
        data_compressed = Zlib::Deflate.deflate(data_uncompressed,
                                                compressed)
        size_uncompressed = data_uncompressed.bytesize
        if size_uncompressed > 4294967295
            raise OutputException, 'uint32 overflow', caller
        end
        size_uncompressed_packed = [size_uncompressed].pack('N')
        return "#{TAG_VERSION.chr}#{TAG_COMPRESSED_ZLIB.chr}" \
               "#{size_uncompressed_packed}#{data_compressed}"
    end
end

Private Class Methods

bignum_to_binary(term) click to toggle source
# File lib/erlang.rb, line 820
def self.bignum_to_binary(term)
    bignum = term.abs
    if term < 0
        sign = 1.chr
    else
        sign = 0.chr
    end
    l = []
    while bignum > 0 do
        l.push((bignum & 255).chr)
        bignum >>= 8
    end
    length = l.length
    if length <= 255
        return "#{TAG_SMALL_BIG_EXT.chr}#{length.chr}#{sign}#{l.join}"
    elsif length <= 4294967295
        length_packed = [length].pack('N')
        return "#{TAG_LARGE_BIG_EXT.chr}#{length_packed}#{sign}#{l.join}"
    else
        raise OutputException, 'uint32 overflow', caller
    end
end
binary_to_atom(i, data) click to toggle source
# File lib/erlang.rb, line 674
def self.binary_to_atom(i, data)
    tag = data[i].ord
    i += 1
    if tag == TAG_ATOM_EXT
        j = data[i,2].unpack('n')[0]
        i += 2
        return [i + j, OtpErlangAtom.new(data[i,j])]
    elsif tag == TAG_ATOM_CACHE_REF
        return [i + 1, OtpErlangAtom.new(data[i,1].ord)]
    elsif tag == TAG_SMALL_ATOM_EXT
        j = data[i,1].ord
        i += 1
        return [i + j, OtpErlangAtom.new(data[i,j])]
    elsif tag == TAG_ATOM_UTF8_EXT
        j = data[i,2].unpack('n')[0]
        i += 2
        atom_name = data[i,j].force_encoding('UTF-8')
        if atom_name.valid_encoding?
            return [i + j, OtpErlangAtom.new(atom_name)]
        else
            raise ParseException, 'invalid atom_name unicode', caller
        end
    elsif tag == TAG_SMALL_ATOM_UTF8_EXT
        j = data[i,1].ord
        i += 1
        atom_name = data[i,j].force_encoding('UTF-8')
        if atom_name.valid_encoding?
            return [i + j, OtpErlangAtom.new(atom_name)]
        else
            raise ParseException, 'invalid atom_name unicode', caller
        end
    else
        raise ParseException, 'invalid atom tag', caller
    end
end
binary_to_integer(i, data) click to toggle source

(binary_to_term Erlang term primitive type functions)

# File lib/erlang.rb, line 630
def self.binary_to_integer(i, data)
    tag = data[i].ord
    i += 1
    if tag == TAG_SMALL_INTEGER_EXT
        return [i + 1, data[i].ord]
    elsif tag == TAG_INTEGER_EXT
        value = data[i,4].unpack('N')[0]
        if 0 != (value & 0x80000000)
            value = -2147483648 + (value & 0x7fffffff)
        end
        return [i + 4, Fixnum.induced_from(value)]
    else
        raise ParseException, 'invalid integer tag', caller
    end
end
binary_to_pid(i, data) click to toggle source
# File lib/erlang.rb, line 646
def self.binary_to_pid(i, data)
    tag = data[i].ord
    i += 1
    if tag == TAG_NEW_PID_EXT
        result = binary_to_atom(i, data)
        i = result[0]; node = result[1]
        id = data[i,4]
        i += 4
        serial = data[i,4]
        i += 4
        creation = data[i,4]
        i += 4
        return [i, OtpErlangPid.new(node, id, serial, creation)]
    elsif tag == TAG_PID_EXT
        result = binary_to_atom(i, data)
        i = result[0]; node = result[1]
        id = data[i,4]
        i += 4
        serial = data[i,4]
        i += 4
        creation = data[i]
        i += 1
        return [i, OtpErlangPid.new(node, id, serial, creation)]
    else
        raise ParseException, 'invalid pid tag', caller
    end
end
binary_to_term_(i, data) click to toggle source

binary_to_term implementation functions

# File lib/erlang.rb, line 363
def self.binary_to_term_(i, data)
    tag = data[i].ord
    i += 1
    if tag == TAG_NEW_FLOAT_EXT
        return [i + 8, data[i,8].unpack('G')[0]]
    elsif tag == TAG_BIT_BINARY_EXT
        j = data[i,4].unpack('N')[0]
        i += 4
        bits = data[i].ord
        i += 1
        return [i + j, OtpErlangBinary.new(data[i,j], bits)]
    elsif tag == TAG_ATOM_CACHE_REF
        return [i + 1, OtpErlangAtom.new(ord(data[i,1]))]
    elsif tag == TAG_SMALL_INTEGER_EXT
        return [i + 1, data[i].ord]
    elsif tag == TAG_INTEGER_EXT
        value = data[i,4].unpack('N')[0]
        if 0 != (value & 0x80000000)
            value = -2147483648 + (value & 0x7fffffff)
        end
        return [i + 4, value]
    elsif tag == TAG_FLOAT_EXT
        value = data[i,31].partition(0.chr)[0].to_f
        return [i + 31, value]
    elsif Set[TAG_V4_PORT_EXT,TAG_NEW_PORT_EXT,
              TAG_REFERENCE_EXT,TAG_PORT_EXT].include?(tag)
        result = binary_to_atom(i, data)
        i = result[0]; node = result[1]
        if tag == TAG_V4_PORT_EXT
            id = data[i,8]
            i += 8
        else
            id = data[i,4]
            i += 4
        end
        if Set[TAG_V4_PORT_EXT,TAG_NEW_PORT_EXT].include?(tag)
            creation = data[i,4]
            i += 4
        else
            creation = data[i]
            i += 1
            if tag == TAG_REFERENCE_EXT
                return [i, OtpErlangReference.new(node, id, creation)]
            end
        end
        # tag == TAG_V4_PORT_EXT or tag == TAG_NEW_PORT_EXT or
        # tag == TAG_PORT_EXT
        return [i, OtpErlangPort.new(node, id, creation)]
    elsif Set[TAG_NEW_PID_EXT, TAG_PID_EXT].include?(tag)
        result = binary_to_atom(i, data)
        i = result[0]; node = result[1]
        id = data[i,4]
        i += 4
        serial = data[i,4]
        i += 4
        if tag == TAG_NEW_PID_EXT
            creation = data[i,4]
            i += 4
        elsif tag == TAG_PID_EXT
            creation = data[i]
            i += 1
        end
        return [i, OtpErlangPid.new(node, id, serial, creation)]
    elsif Set[TAG_SMALL_TUPLE_EXT, TAG_LARGE_TUPLE_EXT].include?(tag)
        if tag == TAG_SMALL_TUPLE_EXT
            length = data[i].ord
            i += 1
        elsif tag == TAG_LARGE_TUPLE_EXT
            length = data[i,4].unpack('N')[0]
            i += 4
        end
        result = binary_to_term_sequence(i, length, data)
        i = result[0]; tmp = result[1]
        return [i, tmp]
    elsif tag == TAG_NIL_EXT
        return [i, OtpErlangList.new([])]
    elsif tag == TAG_STRING_EXT
        j = data[i,2].unpack('n')[0]
        i += 2
        return [i + j, data[i,j]]
    elsif tag == TAG_LIST_EXT
        length = data[i,4].unpack('N')[0]
        i += 4
        result = binary_to_term_sequence(i, length, data)
        i = result[0]; tmp = result[1]
        result = binary_to_term_(i, data)
        i = result[0]; tail = result[1]
        if tail.kind_of?(OtpErlangList) == false or tail.value != []
            tmp.push(tail)
            tmp = OtpErlangList.new(tmp, true)
        else
            tmp = OtpErlangList.new(tmp)
        end
        return [i, tmp]
    elsif tag == TAG_BINARY_EXT
        j = data[i,4].unpack('N')[0]
        i += 4
        return [i + j, OtpErlangBinary.new(data[i,j], 8)]
    elsif Set[TAG_SMALL_BIG_EXT, TAG_LARGE_BIG_EXT].include?(tag)
        if tag == TAG_SMALL_BIG_EXT
            j = data[i].ord
            i += 1
        elsif tag == TAG_LARGE_BIG_EXT
            j = data[i,4].unpack('N')[0]
            i += 4
        end
        sign = data[i].ord
        bignum = 0
        (0...j).each do |bignum_index|
            digit = data[i + j - bignum_index].ord
            bignum = bignum * 256 + digit
        end
        if sign == 1
            bignum *= -1
        end
        i += 1
        return [i + j, bignum]
    elsif tag == TAG_NEW_FUN_EXT
        length = data[i,4].unpack('N')[0]
        return [i + length, OtpErlangFunction.new(tag, data[i,length])]
    elsif tag == TAG_EXPORT_EXT
        old_i = i
        result = binary_to_atom(i, data)
        i = result[0]#; name_module = result[1]
        result = binary_to_atom(i, data)
        i = result[0]#; function = result[1]
        if data[i].ord != TAG_SMALL_INTEGER_EXT
            raise ParseException, 'invalid small integer tag', caller
        end
        i += 1
        #arity = data[i].ord
        i += 1
        return [i, OtpErlangFunction.new(tag, data[old_i,i - old_i])]
    elsif Set[TAG_NEWER_REFERENCE_EXT, TAG_NEW_REFERENCE_EXT].include?(tag)
        j = data[i,2].unpack('n')[0] * 4
        i += 2
        result = binary_to_atom(i, data)
        i = result[0]; node = result[1]
        if tag == TAG_NEWER_REFERENCE_EXT
            creation = data[i,4]
            i += 4
        elsif tag == TAG_NEW_REFERENCE_EXT
            creation = data[i]
            i += 1
        end
        id = data[i,j]
        return [i + j, OtpErlangReference.new(node, id, creation)]
    elsif tag == TAG_MAP_EXT
        length = data[i,4].unpack('N')[0]
        i += 4
        pairs = Hash.new
        (0...length).each do |length_index|
            result = binary_to_term_(i, data)
            i = result[0]; key = result[1]
            result = binary_to_term_(i, data)
            i = result[0]; value = result[1]
            pairs[key] = value
        end
        return [i, pairs]
    elsif tag == TAG_FUN_EXT
        old_i = i
        #numfree = data[i,4].unpack('N')[0]
        i += 4
        result = binary_to_pid(i, data)
        i = result[0]#; pid = result[1]
        result = binary_to_atom(i, data)
        i = result[0]#; name_module = result[1]
        result = binary_to_integer(i, data)
        i = result[0]#; index = result[1]
        result = binary_to_integer(i, data)
        i = result[0]#; uniq = result[1]
        result = binary_to_term_sequence(i, numfree, data)
        i = result[0]#; free = result[1]
        return [i, OtpErlangFunction.new(tag, data[old_i,i - old_i])]
    elsif Set[TAG_ATOM_UTF8_EXT, TAG_ATOM_EXT].include?(tag)
        j = data[i,2].unpack('n')[0]
        i += 2
        atom_name = data[i,j]
        i = i + j
        if atom_name == 'true'
            return [i, true]
        elsif atom_name == 'false'
            return [i, false]
        elsif atom_name == @@UNDEFINED
            return [i, nil]
        else
            if tag == TAG_ATOM_UTF8_EXT
                atom_name = atom_name.force_encoding('UTF-8')
                if atom_name.valid_encoding?
                    return [i, atom_name.to_sym]
                else
                    raise ParseException, 'invalid atom_name unicode', caller
                end
            else
                atom_name = atom_name.force_encoding('ISO-8859-1')
                if atom_name.valid_encoding?
                    return [i, OtpErlangAtom.new(atom_name)]
                else
                    raise ParseException, 'invalid atom_name latin1', caller
                end
            end
        end
    elsif Set[TAG_SMALL_ATOM_UTF8_EXT, TAG_SMALL_ATOM_EXT].include?(tag)
        j = data[i,1].ord
        i += 1
        atom_name = data[i,j]
        i = i + j
        if atom_name == 'true'
            return [i, true]
        elsif atom_name == 'false'
            return [i, false]
        elsif atom_name == @@UNDEFINED
            return [i, nil]
        else
            if tag == TAG_SMALL_ATOM_UTF8_EXT
                atom_name = atom_name.force_encoding('UTF-8')
                if atom_name.valid_encoding?
                    return [i, atom_name.to_sym]
                else
                    raise ParseException, 'invalid atom_name unicode', caller
                end
            else
                atom_name = atom_name.force_encoding('ISO-8859-1')
                if atom_name.valid_encoding?
                    return [i, OtpErlangAtom.new(atom_name)]
                else
                    raise ParseException, 'invalid atom_name latin1', caller
                end
            end
        end
    elsif tag == TAG_COMPRESSED_ZLIB
        size_uncompressed = data[i,4].unpack('N')[0]
        if size_uncompressed == 0
            raise ParseException, 'compressed data null', caller
        end
        i += 4
        data_compressed = data[i..-1]
        j = data_compressed.bytesize
        data_uncompressed = Zlib::Inflate.inflate(data_compressed)
        if size_uncompressed != data_uncompressed.bytesize
            raise ParseException, 'compression corrupt', caller
        end
        result = binary_to_term_(0, data_uncompressed)
        i_new = result[0]; term = result[1]
        if i_new != size_uncompressed
            raise ParseException, 'unparsed data', caller
        end
        return [i + j, term]
    elsif tag == TAG_LOCAL_EXT
        raise ParseException, 'LOCAL_EXT is opaque', caller
    else
        raise ParseException, 'invalid tag', caller
    end
end
binary_to_term_sequence(i, length, data) click to toggle source
# File lib/erlang.rb, line 618
def self.binary_to_term_sequence(i, length, data)
    sequence = []
    (0...length).each do |length_index|
        result = binary_to_term_(i, data)
        i = result[0]; element = result[1]
        sequence.push(element)
    end
    return [i, sequence]
end
float_to_binary(term) click to toggle source
# File lib/erlang.rb, line 843
def self.float_to_binary(term)
    term_packed = [term].pack('G')
    return "#{TAG_NEW_FLOAT_EXT.chr}#{term_packed}"
end
hash_to_binary(term) click to toggle source
# File lib/erlang.rb, line 792
def self.hash_to_binary(term)
    length = term.length
    if length <= 4294967295
        term_packed = term.to_a.map{ |element|
            key_packed = term_to_binary_(element[0])
            value_packed = term_to_binary_(element[1])
            "#{key_packed}#{value_packed}"
        }.join
        length_packed = [length].pack('N')
        return "#{TAG_MAP_EXT.chr}#{length_packed}#{term_packed}"
    else
        raise OutputException, 'uint32 overflow', caller
    end
end
integer_to_binary(term) click to toggle source

(term_to_binary Erlang term primitive type functions)

# File lib/erlang.rb, line 809
def self.integer_to_binary(term)
    if 0 <= term and term <= 255
        return "#{TAG_SMALL_INTEGER_EXT.chr}#{term.chr}"
    elsif -2147483648 <= term and term <= 2147483647
        term_packed = [term].pack('N')
        return "#{TAG_INTEGER_EXT.chr}#{term_packed}"
    else
        return bignum_to_binary(term)
    end
end
string_to_binary(term) click to toggle source

(term_to_binary Erlang term composite type functions)

# File lib/erlang.rb, line 758
def self.string_to_binary(term)
    length = term.bytesize
    if length == 0
        return TAG_NIL_EXT.chr
    elsif length <= 65535
        length_packed = [length].pack('n')
        return "#{TAG_STRING_EXT.chr}#{length_packed}#{term}"
    elsif length <= 4294967295
        length_packed = [length].pack('N')
        term_packed = term.unpack("C#{length}").map{ |c|
            "#{TAG_SMALL_INTEGER_EXT.chr}#{c}"
        }.join
        return "#{TAG_LIST_EXT.chr}#{length_packed}#{term_packed}" \
               "#{TAG_NIL_EXT.chr}"
    else
        raise OutputException, 'uint32 overflow', caller
    end
end
term_to_binary_(term) click to toggle source

term_to_binary implementation functions

# File lib/erlang.rb, line 712
def self.term_to_binary_(term)
    if term.kind_of?(String)
        return string_to_binary(term)
    elsif term.kind_of?(Array)
        return tuple_to_binary(term)
    elsif term.kind_of?(Float)
        return float_to_binary(term)
    elsif term.kind_of?(Integer)
        return integer_to_binary(term)
    elsif term.kind_of?(Hash)
        return hash_to_binary(term)
    elsif term.kind_of?(Symbol)
        return OtpErlangAtom.new(term.to_s).binary
    elsif term.kind_of?(TrueClass)
        return OtpErlangAtom.new(
            'true'.force_encoding('UTF-8')
        ).binary
    elsif term.kind_of?(FalseClass)
        return OtpErlangAtom.new(
            'false'.force_encoding('UTF-8')
        ).binary
    elsif term.nil?
        return OtpErlangAtom.new(
            @@UNDEFINED.force_encoding('UTF-8')
        ).binary
    elsif term.kind_of?(OtpErlangAtom)
        return term.binary
    elsif term.kind_of?(OtpErlangList)
        return term.binary
    elsif term.kind_of?(OtpErlangBinary)
        return term.binary
    elsif term.kind_of?(OtpErlangFunction)
        return term.binary
    elsif term.kind_of?(OtpErlangReference)
        return term.binary
    elsif term.kind_of?(OtpErlangPort)
        return term.binary
    elsif term.kind_of?(OtpErlangPid)
        return term.binary
    else
        raise OutputException, 'unknown ruby type', caller
    end
end
tuple_to_binary(term) click to toggle source
# File lib/erlang.rb, line 777
def self.tuple_to_binary(term)
    length = term.length
    term_packed = term.map{ |element|
        term_to_binary_(element)
    }.join
    if length <= 255
        return "#{TAG_SMALL_TUPLE_EXT.chr}#{length.chr}#{term_packed}"
    elsif length <= 4294967295
        length_packed = [length].pack('N')
        return "#{TAG_LARGE_TUPLE_EXT.chr}#{length_packed}#{term_packed}"
    else
        raise OutputException, 'uint32 overflow', caller
    end
end