lib/qrack/transport/buffer08.rb in bunny-0.6.3.rc2 vs lib/qrack/transport/buffer08.rb in bunny-0.7
- old
+ new
@@ -1,5 +1,7 @@
+# encoding: utf-8
+
if [].map.respond_to? :with_index
class Array #:nodoc:
def enum_with_index
each.with_index
end
@@ -7,270 +9,270 @@
else
require 'enumerator'
end
module Qrack
- module Transport #:nodoc: all
- class Buffer
+ module Transport #:nodoc: all
+ class Buffer
- def initialize data = ''
- @data = data
- @pos = 0
- end
+ def initialize data = ''
+ @data = data
+ @pos = 0
+ end
- attr_reader :pos
-
- def data
- @data.clone
- end
- alias :contents :data
- alias :to_s :data
+ attr_reader :pos
- def << data
- @data << data.to_s
- self
- end
-
- def length
- @data.bytesize
- end
-
- def empty?
- pos == length
- end
-
- def rewind
- @pos = 0
- end
-
- def read_properties *types
- types.shift if types.first == :properties
-
- i = 0
- values = []
+ def data
+ @data.clone
+ end
+ alias :contents :data
+ alias :to_s :data
- while props = read(:short)
- (0..14).each do |n|
- # no more property types
- break unless types[i]
-
- # if flag is set
- if props & (1<<(15-n)) != 0
- if types[i] == :bit
- # bit values exist in flags only
- values << true
- else
- # save type name for later reading
- values << types[i]
- end
- else
- # property not set or is false bit
- values << (types[i] == :bit ? false : nil)
- end
+ def << data
+ @data << data.to_s
+ self
+ end
- i+=1
- end
+ def length
+ @data.bytesize
+ end
- # bit(0) == 0 means no more property flags
- break unless props & 1 == 1
- end
+ def empty?
+ pos == length
+ end
- values.map do |value|
- value.is_a?(Symbol) ? read(value) : value
- end
- end
+ def rewind
+ @pos = 0
+ end
- def read *types
- if types.first == :properties
- return read_properties(*types)
- end
+ def read_properties *types
+ types.shift if types.first == :properties
- values = types.map do |type|
- case type
- when :octet
- _read(1, 'C')
- when :short
- _read(2, 'n')
- when :long
- _read(4, 'N')
- when :longlong
- upper, lower = _read(8, 'NN')
- upper << 32 | lower
- when :shortstr
- _read read(:octet)
- when :longstr
- _read read(:long)
- when :timestamp
- Time.at read(:longlong)
- when :table
- t = Hash.new
+ i = 0
+ values = []
- table = Buffer.new(read(:longstr))
- until table.empty?
- key, type = table.read(:shortstr, :octet)
- key = key.intern
- t[key] ||= case type
- when 83 # 'S'
- table.read(:longstr)
- when 73 # 'I'
- table.read(:long)
- when 68 # 'D'
- exp = table.read(:octet)
- num = table.read(:long)
- num / 10.0**exp
- when 84 # 'T'
- table.read(:timestamp)
- when 70 # 'F'
- table.read(:table)
- end
- end
+ while props = read(:short)
+ (0..14).each do |n|
+ # no more property types
+ break unless types[i]
- t
- when :bit
- if (@bits ||= []).empty?
- val = read(:octet)
- @bits = (0..7).map{|i| (val & 1<<i) != 0 }
- end
+ # if flag is set
+ if props & (1<<(15-n)) != 0
+ if types[i] == :bit
+ # bit values exist in flags only
+ values << true
+ else
+ # save type name for later reading
+ values << types[i]
+ end
+ else
+ # property not set or is false bit
+ values << (types[i] == :bit ? false : nil)
+ end
- @bits.shift
- else
- raise Qrack::InvalidTypeError, "Cannot read data of type #{type}"
- end
- end
-
- types.size == 1 ? values.first : values
- end
-
- def write type, data
- case type
- when :octet
- _write(data, 'C')
- when :short
- _write(data, 'n')
- when :long
- _write(data, 'N')
- when :longlong
- lower = data & 0xffffffff
- upper = (data & ~0xffffffff) >> 32
- _write([upper, lower], 'NN')
- when :shortstr
- data = (data || '').to_s
- _write([data.bytesize, data], 'Ca*')
- when :longstr
- if data.is_a? Hash
- write(:table, data)
- else
- data = (data || '').to_s
- _write([data.bytesize, data], 'Na*')
- end
- when :timestamp
- write(:longlong, data.to_i)
- when :table
- data ||= {}
- write :longstr, (data.inject(Buffer.new) do |table, (key, value)|
- table.write(:shortstr, key.to_s)
+ i+=1
+ end
- case value
- when String
- table.write(:octet, 83) # 'S'
- table.write(:longstr, value.to_s)
- when Fixnum
- table.write(:octet, 73) # 'I'
- table.write(:long, value)
- when Float
- table.write(:octet, 68) # 'D'
- # XXX there's gotta be a better way to do this..
- exp = value.to_s.split('.').last.bytesize
- num = value * 10**exp
- table.write(:octet, exp)
- table.write(:long, num)
- when Time
- table.write(:octet, 84) # 'T'
- table.write(:timestamp, value)
- when Hash
- table.write(:octet, 70) # 'F'
- table.write(:table, value)
- end
+ # bit(0) == 0 means no more property flags
+ break unless props & 1 == 1
+ end
- table
- end)
- when :bit
- [*data].to_enum(:each_slice, 8).each{|bits|
- write(:octet, bits.enum_with_index.inject(0){ |byte, (bit, i)|
- byte |= 1<<i if bit
- byte
- })
- }
- when :properties
- values = []
- data.enum_with_index.inject(0) do |short, ((type, value), i)|
- n = i % 15
- last = i+1 == data.size
+ values.map do |value|
+ value.is_a?(Symbol) ? read(value) : value
+ end
+ end
- if (n == 0 and i != 0) or last
- if data.size > i+1
- short |= 1<<0
- elsif last and value
- values << [type,value]
- short |= 1<<(15-n)
- end
+ def read *types
+ if types.first == :properties
+ return read_properties(*types)
+ end
- write(:short, short)
- short = 0
- end
+ values = types.map do |type|
+ case type
+ when :octet
+ _read(1, 'C')
+ when :short
+ _read(2, 'n')
+ when :long
+ _read(4, 'N')
+ when :longlong
+ upper, lower = _read(8, 'NN')
+ upper << 32 | lower
+ when :shortstr
+ _read read(:octet)
+ when :longstr
+ _read read(:long)
+ when :timestamp
+ Time.at read(:longlong)
+ when :table
+ t = Hash.new
- if value and !last
- values << [type,value]
- short |= 1<<(15-n)
- end
+ table = Buffer.new(read(:longstr))
+ until table.empty?
+ key, type = table.read(:shortstr, :octet)
+ key = key.intern
+ t[key] ||= case type
+ when 83 # 'S'
+ table.read(:longstr)
+ when 73 # 'I'
+ table.read(:long)
+ when 68 # 'D'
+ exp = table.read(:octet)
+ num = table.read(:long)
+ num / 10.0**exp
+ when 84 # 'T'
+ table.read(:timestamp)
+ when 70 # 'F'
+ table.read(:table)
+ end
+ end
- short
- end
-
- values.each do |type, value|
- write(type, value) unless type == :bit
- end
- else
- raise Qrack::InvalidTypeError, "Cannot write data of type #{type}"
- end
-
- self
- end
+ t
+ when :bit
+ if (@bits ||= []).empty?
+ val = read(:octet)
+ @bits = (0..7).map{|i| (val & (1 << i)) != 0 }
+ end
- def extract
- begin
- cur_data, cur_pos = @data.clone, @pos
- yield self
- rescue Qrack::BufferOverflowError
- @data, @pos = cur_data, cur_pos
- nil
- end
- end
+ @bits.shift
+ else
+ raise Qrack::InvalidTypeError, "Cannot read data of type #{type}"
+ end
+ end
- def _read(size, pack = nil)
- if @data.is_a?(Qrack::Client)
- raw = @data.read(size)
- return raw if raw.nil? or pack.nil?
- return raw.unpack(pack).first
- end
+ types.size == 1 ? values.first : values
+ end
- if @pos + size > length
- raise Qrack::BufferOverflowError
- else
- data = @data[@pos,size]
- @data[@pos,size] = ''
- if pack
- data = data.unpack(pack)
- data = data.pop if data.size == 1
- end
- data
- end
- end
-
- def _write data, pack = nil
- data = [*data].pack(pack) if pack
- @data[@pos,0] = data
- @pos += data.bytesize
- end
- end
- end
+ def write type, data
+ case type
+ when :octet
+ _write(data, 'C')
+ when :short
+ _write(data, 'n')
+ when :long
+ _write(data, 'N')
+ when :longlong
+ lower = data & 0xffffffff
+ upper = (data & ~0xffffffff) >> 32
+ _write([upper, lower], 'NN')
+ when :shortstr
+ data = (data || '').to_s
+ _write([data.bytesize, data], 'Ca*')
+ when :longstr
+ if data.is_a? Hash
+ write(:table, data)
+ else
+ data = (data || '').to_s
+ _write([data.bytesize, data], 'Na*')
+ end
+ when :timestamp
+ write(:longlong, data.to_i)
+ when :table
+ data ||= {}
+ write :longstr, (data.inject(Buffer.new) do |table, (key, value)|
+ table.write(:shortstr, key.to_s)
+
+ case value
+ when String
+ table.write(:octet, 83) # 'S'
+ table.write(:longstr, value.to_s)
+ when Fixnum
+ table.write(:octet, 73) # 'I'
+ table.write(:long, value)
+ when Float
+ table.write(:octet, 68) # 'D'
+ # XXX there's gotta be a better way to do this..
+ exp = value.to_s.split('.').last.bytesize
+ num = value * 10**exp
+ table.write(:octet, exp)
+ table.write(:long, num)
+ when Time
+ table.write(:octet, 84) # 'T'
+ table.write(:timestamp, value)
+ when Hash
+ table.write(:octet, 70) # 'F'
+ table.write(:table, value)
+ end
+
+ table
+ end)
+ when :bit
+ [*data].to_enum(:each_slice, 8).each{|bits|
+ write(:octet, bits.enum_with_index.inject(0){ |byte, (bit, i)|
+ byte |= (1 << i) if bit
+ byte
+ })
+ }
+ when :properties
+ values = []
+ data.enum_with_index.inject(0) do |short, ((type, value), i)|
+ n = i % 15
+ last = i+1 == data.size
+
+ if (n == 0 and i != 0) or last
+ if data.size > i+1
+ short |= (1 << 0)
+ elsif last and value
+ values << [type,value]
+ short |= 1<<(15-n)
+ end
+
+ write(:short, short)
+ short = 0
+ end
+
+ if value and !last
+ values << [type,value]
+ short |= 1<<(15-n)
+ end
+
+ short
+ end
+
+ values.each do |type, value|
+ write(type, value) unless type == :bit
+ end
+ else
+ raise Qrack::InvalidTypeError, "Cannot write data of type #{type}"
+ end
+
+ self
+ end
+
+ def extract
+ begin
+ cur_data, cur_pos = @data.clone, @pos
+ yield self
+ rescue Qrack::BufferOverflowError
+ @data, @pos = cur_data, cur_pos
+ nil
+ end
+ end
+
+ def _read(size, pack = nil)
+ if @data.is_a?(Qrack::Client)
+ raw = @data.read(size)
+ return raw if raw.nil? or pack.nil?
+ return raw.unpack(pack).first
+ end
+
+ if @pos + size > length
+ raise Qrack::BufferOverflowError
+ else
+ data = @data[@pos,size]
+ @data[@pos,size] = ''
+ if pack
+ data = data.unpack(pack)
+ data = data.pop if data.size == 1
+ end
+ data
+ end
+ end
+
+ def _write data, pack = nil
+ data = [*data].pack(pack) if pack
+ @data[@pos,0] = data
+ @pos += data.bytesize
+ end
+ end
+ end
end