amq-protocol 2.3.4 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +23 -0
  3. data/CLAUDE.md +1 -0
  4. data/ChangeLog.md +30 -3
  5. data/GEMINI.md +1 -0
  6. data/Gemfile +5 -0
  7. data/README.md +2 -7
  8. data/benchmarks/frame_encoding.rb +75 -0
  9. data/benchmarks/method_encoding.rb +198 -0
  10. data/benchmarks/pack_unpack.rb +158 -0
  11. data/benchmarks/run_all.rb +64 -0
  12. data/benchmarks/table_encoding.rb +110 -0
  13. data/lib/amq/bit_set.rb +1 -0
  14. data/lib/amq/endianness.rb +2 -0
  15. data/lib/amq/int_allocator.rb +1 -0
  16. data/lib/amq/pack.rb +33 -42
  17. data/lib/amq/protocol/client.rb +30 -37
  18. data/lib/amq/protocol/constants.rb +2 -0
  19. data/lib/amq/protocol/exceptions.rb +3 -1
  20. data/lib/amq/protocol/float_32bit.rb +2 -0
  21. data/lib/amq/protocol/frame.rb +9 -3
  22. data/lib/amq/protocol/table.rb +20 -17
  23. data/lib/amq/protocol/table_value_decoder.rb +48 -52
  24. data/lib/amq/protocol/table_value_encoder.rb +1 -0
  25. data/lib/amq/protocol/type_constants.rb +1 -0
  26. data/lib/amq/protocol/version.rb +1 -1
  27. data/lib/amq/settings.rb +1 -0
  28. data/spec/amq/bit_set_spec.rb +22 -0
  29. data/spec/amq/endianness_spec.rb +23 -0
  30. data/spec/amq/int_allocator_spec.rb +26 -3
  31. data/spec/amq/pack_spec.rb +14 -24
  32. data/spec/amq/protocol/exceptions_spec.rb +70 -0
  33. data/spec/amq/protocol/float_32bit_spec.rb +27 -0
  34. data/spec/amq/protocol/frame_spec.rb +64 -0
  35. data/spec/amq/protocol/table_spec.rb +32 -0
  36. data/spec/amq/protocol/value_decoder_spec.rb +97 -0
  37. data/spec/amq/protocol/value_encoder_spec.rb +21 -0
  38. data/spec/amq/settings_spec.rb +37 -1
  39. data/spec/amq/uri_parsing_spec.rb +7 -0
  40. metadata +14 -3
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # frozen_string_literal: true
4
+
5
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
6
+
7
+ require "amq/protocol/client"
8
+ require "benchmark/ips"
9
+
10
+ puts
11
+ puts "-" * 80
12
+ puts "Table Encoding/Decoding Benchmarks on #{RUBY_DESCRIPTION}"
13
+ puts "-" * 80
14
+
15
+ # Test data - various table sizes and types
16
+ EMPTY_TABLE = {}
17
+
18
+ SIMPLE_TABLE = {
19
+ "key1" => "value1",
20
+ "key2" => 42,
21
+ "key3" => true
22
+ }.freeze
23
+
24
+ TYPICAL_HEADERS = {
25
+ "content_type" => "application/json",
26
+ "content_encoding" => "utf-8",
27
+ "x-custom-header" => "some-value",
28
+ "x-retry-count" => 3,
29
+ "x-timestamp" => Time.now.to_i
30
+ }.freeze
31
+
32
+ COMPLEX_TABLE = {
33
+ "string" => "hello world",
34
+ "integer" => 123456789,
35
+ "float" => 3.14159,
36
+ "boolean_true" => true,
37
+ "boolean_false" => false,
38
+ "nested" => {
39
+ "inner_key" => "inner_value",
40
+ "inner_number" => 999
41
+ },
42
+ "array" => [1, 2, 3, "four", true]
43
+ }.freeze
44
+
45
+ LARGE_TABLE = (1..50).to_h { |i| ["key_#{i}", "value_#{i}"] }.freeze
46
+
47
+ # Pre-encode tables for decode benchmarks
48
+ ENCODED_EMPTY = AMQ::Protocol::Table.encode(EMPTY_TABLE)
49
+ ENCODED_SIMPLE = AMQ::Protocol::Table.encode(SIMPLE_TABLE)
50
+ ENCODED_TYPICAL = AMQ::Protocol::Table.encode(TYPICAL_HEADERS)
51
+ ENCODED_COMPLEX = AMQ::Protocol::Table.encode(COMPLEX_TABLE)
52
+ ENCODED_LARGE = AMQ::Protocol::Table.encode(LARGE_TABLE)
53
+
54
+ puts "Table sizes (bytes): empty=#{ENCODED_EMPTY.bytesize}, simple=#{ENCODED_SIMPLE.bytesize}, typical=#{ENCODED_TYPICAL.bytesize}, complex=#{ENCODED_COMPLEX.bytesize}, large=#{ENCODED_LARGE.bytesize}"
55
+ puts
56
+
57
+ puts "=== Table Encoding ==="
58
+ Benchmark.ips do |x|
59
+ x.config(time: 5, warmup: 2)
60
+
61
+ x.report("encode empty") do
62
+ AMQ::Protocol::Table.encode(EMPTY_TABLE)
63
+ end
64
+
65
+ x.report("encode simple (3 keys)") do
66
+ AMQ::Protocol::Table.encode(SIMPLE_TABLE)
67
+ end
68
+
69
+ x.report("encode typical headers (5 keys)") do
70
+ AMQ::Protocol::Table.encode(TYPICAL_HEADERS)
71
+ end
72
+
73
+ x.report("encode complex (nested/array)") do
74
+ AMQ::Protocol::Table.encode(COMPLEX_TABLE)
75
+ end
76
+
77
+ x.report("encode large (50 keys)") do
78
+ AMQ::Protocol::Table.encode(LARGE_TABLE)
79
+ end
80
+
81
+ x.compare!
82
+ end
83
+
84
+ puts
85
+ puts "=== Table Decoding ==="
86
+ Benchmark.ips do |x|
87
+ x.config(time: 5, warmup: 2)
88
+
89
+ x.report("decode empty") do
90
+ AMQ::Protocol::Table.decode(ENCODED_EMPTY)
91
+ end
92
+
93
+ x.report("decode simple (3 keys)") do
94
+ AMQ::Protocol::Table.decode(ENCODED_SIMPLE)
95
+ end
96
+
97
+ x.report("decode typical headers (5 keys)") do
98
+ AMQ::Protocol::Table.decode(ENCODED_TYPICAL)
99
+ end
100
+
101
+ x.report("decode complex (nested/array)") do
102
+ AMQ::Protocol::Table.decode(ENCODED_COMPLEX)
103
+ end
104
+
105
+ x.report("decode large (50 keys)") do
106
+ AMQ::Protocol::Table.decode(ENCODED_LARGE)
107
+ end
108
+
109
+ x.compare!
110
+ end
data/lib/amq/bit_set.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module AMQ
4
5
  # Very minimalistic, pure Ruby implementation of bit set. Inspired by java.util.BitSet,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AMQ
2
4
  module Endianness
3
5
  BIG_ENDIAN = ([1].pack("s") == "\x00\x01")
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "amq/bit_set"
4
5
 
data/lib/amq/pack.rb CHANGED
@@ -1,54 +1,45 @@
1
1
  # encoding: binary
2
-
3
- require 'amq/endianness'
2
+ # frozen_string_literal: true
4
3
 
5
4
  module AMQ
6
- # Implements pack to/unpack from 64bit string in network byte order
7
- # compatible with Ruby 1.8+.
5
+ # Implements pack to/unpack from 64bit string in network byte order.
6
+ # Uses native Ruby pack directives with explicit endianness (Ruby 1.9.3+).
8
7
  module Pack
9
- UINT64 = "Q".freeze
10
- UINT16_BE = "n".freeze
11
- INT16 = "c".freeze
12
-
13
- if Endianness.big_endian?
14
- def self.pack_uint64_big_endian(long_long)
15
- [long_long].pack(UINT64)
16
- end
17
-
18
- def self.unpack_uint64_big_endian(data)
19
- data.unpack(UINT64)
20
- end
21
-
22
- def self.pack_int16_big_endian(short)
23
- [long_long].pack(INT16)
24
- end
25
-
26
- def self.unpack_int16_big_endian(data)
27
- data.unpack(INT16)
28
- end
29
- else
30
- def self.pack_uint64_big_endian(long_long)
31
- result = [long_long].pack(UINT64)
32
- result.bytes.to_a.reverse.map(&:chr).join
33
- end
8
+ # Pack format strings - frozen for performance
9
+ UINT64_BE = 'Q>'.freeze # 64-bit unsigned, big-endian
10
+ INT64_BE = 'q>'.freeze # 64-bit signed, big-endian
11
+ INT16_BE = 's>'.freeze # 16-bit signed, big-endian
12
+ UINT16_BE = 'n'.freeze # 16-bit unsigned, big-endian (network order)
13
+
14
+ # Packs a 64-bit unsigned integer to big-endian binary string.
15
+ # @param long_long [Integer] The value to pack
16
+ # @return [String] 8-byte binary string in big-endian order
17
+ def self.pack_uint64_big_endian(long_long)
18
+ [long_long].pack(UINT64_BE)
19
+ end
34
20
 
35
- def self.unpack_uint64_big_endian(data)
36
- data = data.bytes.to_a.reverse.map(&:chr).join
37
- data.unpack(UINT64)
38
- end
21
+ # Unpacks a big-endian binary string to a 64-bit unsigned integer.
22
+ # @param data [String] 8-byte binary string in big-endian order
23
+ # @return [Array<Integer>] Single-element array containing the unpacked value
24
+ def self.unpack_uint64_big_endian(data)
25
+ data.unpack(UINT64_BE)
26
+ end
39
27
 
40
- def self.pack_int16_big_endian(short)
41
- result = [long_long].pack(INT16)
42
- result.bytes.to_a.reverse.map(&:chr).join
43
- end
28
+ # Packs a 16-bit signed integer to big-endian binary string.
29
+ # @param short [Integer] The value to pack
30
+ # @return [String] 2-byte binary string in big-endian order
31
+ def self.pack_int16_big_endian(short)
32
+ [short].pack(INT16_BE)
33
+ end
44
34
 
45
- def self.unpack_int16_big_endian(data)
46
- value = data.bytes.to_a.map(&:chr).join.unpack(UINT16_BE)[0]
47
- [(value & ~(1 << 15)) - (value & (1 << 15))]
48
- end
35
+ # Unpacks a big-endian binary string to a 16-bit signed integer.
36
+ # @param data [String] 2-byte binary string in big-endian order
37
+ # @return [Array<Integer>] Single-element array containing the unpacked value
38
+ def self.unpack_int16_big_endian(data)
39
+ data.unpack(INT16_BE)
49
40
  end
50
41
  end
51
42
 
52
- # Backwards compatibility
43
+ # Backwards compatibility alias
53
44
  Hacks = Pack
54
45
  end
@@ -1569,30 +1569,31 @@ module AMQ
1569
1569
  0x0004,
1570
1570
  ]
1571
1571
 
1572
+ # Optimized decode_properties using getbyte and unpack1
1572
1573
  def self.decode_properties(data)
1573
1574
  offset, data_length, properties = 0, data.bytesize, {}
1574
1575
 
1575
- compressed_index = data[offset, 2].unpack(PACK_UINT16)[0]
1576
+ compressed_index = data.byteslice(offset, 2).unpack1(PACK_UINT16)
1576
1577
  offset += 2
1577
1578
  while data_length > offset
1578
1579
  DECODE_PROPERTIES_KEYS.each do |key|
1579
1580
  next unless compressed_index >= key
1580
1581
  compressed_index -= key
1581
- name = DECODE_PROPERTIES[key] || raise(RuntimeError.new("No property found for index #{index.inspect}!"))
1582
+ name = DECODE_PROPERTIES[key] || raise(RuntimeError.new("No property found for index #{key.inspect}!"))
1582
1583
  case DECODE_PROPERTIES_TYPE[key]
1583
1584
  when :shortstr
1584
- size = data[offset, 1].unpack(PACK_CHAR)[0]
1585
+ size = data.getbyte(offset)
1585
1586
  offset += 1
1586
- result = data[offset, size]
1587
+ result = data.byteslice(offset, size)
1587
1588
  when :octet
1588
1589
  size = 1
1589
- result = data[offset, size].unpack(PACK_CHAR).first
1590
+ result = data.getbyte(offset)
1590
1591
  when :timestamp
1591
1592
  size = 8
1592
- result = Time.at(data[offset, size].unpack(PACK_UINT64_BE).last)
1593
+ result = Time.at(data.byteslice(offset, 8).unpack1(PACK_UINT64_BE))
1593
1594
  when :table
1594
- size = 4 + data[offset, 4].unpack(PACK_UINT32)[0]
1595
- result = Table.decode(data[offset, size])
1595
+ size = 4 + data.byteslice(offset, 4).unpack1(PACK_UINT32)
1596
+ result = Table.decode(data.byteslice(offset, size))
1596
1597
  end
1597
1598
  properties[name] = result
1598
1599
  offset += size
@@ -1688,13 +1689,11 @@ module AMQ
1688
1689
  @index = 0x003C0015 # 60, 21, 3932181
1689
1690
  @packed_indexes = [60, 21].pack(PACK_UINT16_X2).freeze
1690
1691
 
1692
+ # Optimized decode using getbyte
1691
1693
  # @return
1692
1694
  def self.decode(data)
1693
- offset = offset = 0 # self-assigning offset to eliminate "assigned but unused variable" warning even if offset is not used in this method
1694
- length = data[offset, 1].unpack(PACK_CHAR).first
1695
- offset += 1
1696
- consumer_tag = data[offset, length]
1697
- offset += length
1695
+ length = data.getbyte(0)
1696
+ consumer_tag = data.byteslice(1, length)
1698
1697
  self.new(consumer_tag)
1699
1698
  end
1700
1699
 
@@ -1866,26 +1865,25 @@ module AMQ
1866
1865
  @index = 0x003C003C # 60, 60, 3932220
1867
1866
  @packed_indexes = [60, 60].pack(PACK_UINT16_X2).freeze
1868
1867
 
1868
+ # Optimized decode using getbyte and unpack1 for better performance
1869
1869
  # @return
1870
1870
  def self.decode(data)
1871
- offset = offset = 0 # self-assigning offset to eliminate "assigned but unused variable" warning even if offset is not used in this method
1872
- length = data[offset, 1].unpack(PACK_CHAR).first
1871
+ offset = 0
1872
+ length = data.getbyte(offset)
1873
1873
  offset += 1
1874
- consumer_tag = data[offset, length]
1874
+ consumer_tag = data.byteslice(offset, length)
1875
1875
  offset += length
1876
- delivery_tag = AMQ::Pack.unpack_uint64_big_endian(data[offset, 8]).first
1876
+ delivery_tag = data.byteslice(offset, 8).unpack1(PACK_UINT64_BE)
1877
1877
  offset += 8
1878
- bit_buffer = data[offset, 1].unpack(PACK_CHAR).first
1878
+ redelivered = (data.getbyte(offset) & 1) != 0
1879
1879
  offset += 1
1880
- redelivered = (bit_buffer & (1 << 0)) != 0
1881
- length = data[offset, 1].unpack(PACK_CHAR).first
1880
+ length = data.getbyte(offset)
1882
1881
  offset += 1
1883
- exchange = data[offset, length]
1882
+ exchange = data.byteslice(offset, length)
1884
1883
  offset += length
1885
- length = data[offset, 1].unpack(PACK_CHAR).first
1884
+ length = data.getbyte(offset)
1886
1885
  offset += 1
1887
- routing_key = data[offset, length]
1888
- offset += length
1886
+ routing_key = data.byteslice(offset, length)
1889
1887
  self.new(consumer_tag, delivery_tag, redelivered, exchange, routing_key)
1890
1888
  end
1891
1889
 
@@ -2009,14 +2007,11 @@ module AMQ
2009
2007
  @index = 0x003C0050 # 60, 80, 3932240
2010
2008
  @packed_indexes = [60, 80].pack(PACK_UINT16_X2).freeze
2011
2009
 
2010
+ # Optimized decode using unpack1 and getbyte
2012
2011
  # @return
2013
2012
  def self.decode(data)
2014
- offset = offset = 0 # self-assigning offset to eliminate "assigned but unused variable" warning even if offset is not used in this method
2015
- delivery_tag = AMQ::Pack.unpack_uint64_big_endian(data[offset, 8]).first
2016
- offset += 8
2017
- bit_buffer = data[offset, 1].unpack(PACK_CHAR).first
2018
- offset += 1
2019
- multiple = (bit_buffer & (1 << 0)) != 0
2013
+ delivery_tag = data.byteslice(0, 8).unpack1(PACK_UINT64_BE)
2014
+ multiple = (data.getbyte(8) & 1) != 0
2020
2015
  self.new(delivery_tag, multiple)
2021
2016
  end
2022
2017
 
@@ -2141,15 +2136,13 @@ module AMQ
2141
2136
  @index = 0x003C0078 # 60, 120, 3932280
2142
2137
  @packed_indexes = [60, 120].pack(PACK_UINT16_X2).freeze
2143
2138
 
2139
+ # Optimized decode using unpack1 and getbyte
2144
2140
  # @return
2145
2141
  def self.decode(data)
2146
- offset = offset = 0 # self-assigning offset to eliminate "assigned but unused variable" warning even if offset is not used in this method
2147
- delivery_tag = AMQ::Pack.unpack_uint64_big_endian(data[offset, 8]).first
2148
- offset += 8
2149
- bit_buffer = data[offset, 1].unpack(PACK_CHAR).first
2150
- offset += 1
2151
- multiple = (bit_buffer & (1 << 0)) != 0
2152
- requeue = (bit_buffer & (1 << 1)) != 0
2142
+ delivery_tag = data.byteslice(0, 8).unpack1(PACK_UINT64_BE)
2143
+ bit_buffer = data.getbyte(8)
2144
+ multiple = (bit_buffer & 1) != 0
2145
+ requeue = (bit_buffer & 2) != 0
2153
2146
  self.new(delivery_tag, multiple, requeue)
2154
2147
  end
2155
2148
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AMQ
2
4
  module Protocol
3
5
  TLS_PORT = 5671
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AMQ
2
4
  module Protocol
3
5
  class Error < StandardError
@@ -41,7 +43,7 @@ module AMQ
41
43
 
42
44
  class BadResponseError < Protocol::Error
43
45
  def initialize(argument, expected, actual)
44
- super("Argument #{argument} has to be #{expected.inspect}, was #{data.inspect}")
46
+ super("Argument #{argument} has to be #{expected.inspect}, was #{actual.inspect}")
45
47
  end
46
48
  end
47
49
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AMQ
2
4
  module Protocol
3
5
  # Allows distinguishing between 32-bit and 64-bit floats in Ruby.
@@ -1,4 +1,5 @@
1
1
  # encoding: binary
2
+ # frozen_string_literal: true
2
3
 
3
4
  module AMQ
4
5
  module Protocol
@@ -9,6 +10,9 @@ module AMQ
9
10
  CHANNEL_RANGE = (0..65535).freeze
10
11
  FINAL_OCTET = "\xCE".freeze # 206
11
12
 
13
+ # Pack format for 64-bit unsigned big-endian
14
+ PACK_UINT64_BE = 'Q>'.freeze
15
+
12
16
  def self.encoded_payload(payload)
13
17
  if payload.respond_to?(:force_encoding) && payload.encoding.name != 'BINARY'
14
18
  # Only copy if we have to.
@@ -56,9 +60,11 @@ This functionality is part of the https://github.com/ruby-amqp/amq-client librar
56
60
  EOF
57
61
  end
58
62
 
63
+ # Optimized header decode using unpack1 for single values where appropriate
59
64
  def self.decode_header(header)
60
65
  raise EmptyResponseError if header == nil || header.empty?
61
66
 
67
+ # Use unpack for multiple values - this is the optimal approach
62
68
  type_id, channel, size = header.unpack(PACK_CHAR_UINT16_UINT32)
63
69
  type = TYPES_REVERSE[type_id]
64
70
  raise FrameTypeError.new(TYPES_OPTIONS) unless type
@@ -130,7 +136,7 @@ This functionality is part of the https://github.com/ruby-amqp/amq-client librar
130
136
  end # final?
131
137
 
132
138
  def decode_payload
133
- self.method_class.decode(@payload[4..-1])
139
+ self.method_class.decode(@payload.byteslice(4..-1))
134
140
  end
135
141
  end
136
142
 
@@ -167,8 +173,8 @@ This functionality is part of the https://github.com/ruby-amqp/amq-client librar
167
173
  # the total size of the content body, that is, the sum of the body sizes for the
168
174
  # following content body frames. Zero indicates that there are no content body frames.
169
175
  # So this is NOT related to this very header frame!
170
- @body_size = AMQ::Hacks.unpack_uint64_big_endian(@payload[4..11]).first
171
- @data = @payload[12..-1]
176
+ @body_size = @payload.byteslice(4, 8).unpack1(PACK_UINT64_BE)
177
+ @data = @payload.byteslice(12..-1)
172
178
  @properties = Basic.decode_properties(@data)
173
179
  end
174
180
  end
@@ -1,4 +1,5 @@
1
1
  # encoding: binary
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "amq/protocol/type_constants"
4
5
  require "amq/protocol/table_value_encoder"
@@ -14,6 +15,8 @@ module AMQ
14
15
 
15
16
  include TypeConstants
16
17
 
18
+ # Pack format string
19
+ PACK_UINT32_BE = 'N'.freeze
17
20
 
18
21
  #
19
22
  # API
@@ -27,16 +30,16 @@ module AMQ
27
30
 
28
31
 
29
32
  def self.encode(table)
30
- buffer = String.new
33
+ buffer = +''
31
34
 
32
35
  table ||= {}
33
36
 
34
37
  table.each do |key, value|
35
38
  key = key.to_s # it can be a symbol as well
36
- buffer << key.bytesize.chr + key
39
+ buffer << key.bytesize.chr << key
37
40
 
38
41
  case value
39
- when Hash then
42
+ when Hash
40
43
  buffer << TYPE_HASH
41
44
  buffer << self.encode(value)
42
45
  else
@@ -44,15 +47,15 @@ module AMQ
44
47
  end
45
48
  end
46
49
 
47
- [buffer.bytesize].pack(PACK_UINT32).force_encoding(buffer.encoding) + buffer
50
+ [buffer.bytesize].pack(PACK_UINT32_BE) << buffer
48
51
  end
49
52
 
50
53
 
51
54
 
52
55
 
53
56
  def self.decode(data)
54
- table = Hash.new
55
- table_length = data.unpack(PACK_UINT32).first
57
+ table = {}
58
+ table_length = data.unpack1(PACK_UINT32_BE)
56
59
 
57
60
  return table if table_length.zero?
58
61
 
@@ -86,19 +89,19 @@ module AMQ
86
89
  when TYPE_BOOLEAN
87
90
  v, offset = TableValueDecoder.decode_boolean(data, offset)
88
91
  v
89
- when TYPE_BYTE then
92
+ when TYPE_BYTE
90
93
  v, offset = TableValueDecoder.decode_byte(data, offset)
91
94
  v
92
- when TYPE_SIGNED_16BIT then
95
+ when TYPE_SIGNED_16BIT
93
96
  v, offset = TableValueDecoder.decode_short(data, offset)
94
97
  v
95
- when TYPE_SIGNED_64BIT then
98
+ when TYPE_SIGNED_64BIT
96
99
  v, offset = TableValueDecoder.decode_long(data, offset)
97
100
  v
98
- when TYPE_32BIT_FLOAT then
101
+ when TYPE_32BIT_FLOAT
99
102
  v, offset = TableValueDecoder.decode_32bit_float(data, offset)
100
103
  v
101
- when TYPE_64BIT_FLOAT then
104
+ when TYPE_64BIT_FLOAT
102
105
  v, offset = TableValueDecoder.decode_64bit_float(data, offset)
103
106
  v
104
107
  when TYPE_VOID
@@ -112,11 +115,11 @@ module AMQ
112
115
  end
113
116
 
114
117
  table
115
- end # self.decode
118
+ end
116
119
 
117
120
 
118
121
  def self.length(data)
119
- data.unpack(PACK_UINT32).first
122
+ data.unpack1(PACK_UINT32_BE)
120
123
  end
121
124
 
122
125
 
@@ -128,17 +131,17 @@ module AMQ
128
131
  end
129
132
 
130
133
  acc
131
- end # self.hash_size(value)
134
+ end
132
135
 
133
136
 
134
137
  def self.decode_table_key(data, offset)
135
- key_length = data.slice(offset, 1).unpack(PACK_CHAR).first
138
+ key_length = data.getbyte(offset)
136
139
  offset += 1
137
- key = data.slice(offset, key_length)
140
+ key = data.byteslice(offset, key_length)
138
141
  offset += key_length
139
142
 
140
143
  [key, offset]
141
- end # self.decode_table_key(data, offset)
144
+ end
142
145
 
143
146
 
144
147