blob: 418388c73ae5b93f37f1349a71723a709cc6d22a [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
module Qpid
def self.struct(type, *args)
# FIXME: This is fragile; the last arg could be a hash,
# without being hte keywords
kwargs = {}
kwargs = args.pop if args.any? && args[-1].is_a?(Hash)
if args.size > type.fields.size
raise TypeError,
"%s() takes at most %d arguments (%d given)" %
[type.name, type.fields.size, args.size]
end
attrs = type.fields.inject({}) do |attrs, field|
if args.any?
attrs[field.name] = args.shift
if kwargs.key?(field.name)
raise TypeError,
"%s() got multiple values for keyword argument '%s'" %
[type.name, field.name]
end
elsif kwargs.key?(field.name)
attrs[field.name] = kwargs.delete(field.name)
else
attrs[field.name] = field.default
end
attrs
end
unless kwargs.empty?
unexpected = kwargs.keys[0]
raise TypeError,
"%s() got an unexpected keyword argument '%s'" %
[type.name, unexpected]
end
attrs[:st_type] = type
attrs[:id] = nil
name = "Qpid_" + type.name.to_s.capitalize
unless ::Struct.const_defined?(name)
vars = type.fields.collect { |f| f.name } << :st_type << :id
::Struct.new(name, *vars)
end
st = ::Struct.const_get(name)
result = st.new
attrs.each { |k, v| result[k] = v }
return result
end
class Message
attr_accessor :headers, :body, :id
def initialize(*args)
@body = nil
@headers = nil
@body = args.pop unless args.empty?
@headers = args unless args.empty?
@id = nil
end
def has(name)
return ! get(name).nil?
end
def get(name)
if @headers
name = name.to_sym
@headers.find { |h| h.st_type.name == name }
end
end
def set(header)
@headers ||= []
if h = @headers.find { |h| h.st_type == header.st_type }
ind = @headers.index(h)
@headers[ind] = header
else
@headers << header
end
end
def clear(name)
if @headers
name = name.to_sym
@headers.delete_if { |h| h.st_type.name == name }
end
end
# FIXME: Not sure what to do here
# Ruby doesn't have a notion of a evaluable string representation
# def __repr__(self):
# args = []
# if self.headers:
# args.extend(map(repr, self.headers))
# if self.body:
# args.append(repr(self.body))
# if self.id is not None:
# args.append("id=%s" % self.id)
# return "Message(%s)" % ", ".join(args)
# end
end
class ::Object
def to_serial
Qpid::Serial.new(self)
end
end
class Serial
include Comparable
attr_accessor :value
def initialize(value)
@value = value & 0xFFFFFFFF
end
def hash
@value.hash
end
def to_serial
self
end
def eql?(other)
other = other.to_serial
value.eql?(other.value)
end
def <=>(other)
return 1 if other.nil?
other = other.to_serial
delta = (value - other.value) & 0xFFFFFFFF
neg = delta & 0x80000000
mag = delta & 0x7FFFFFFF
return (neg>0) ? -mag : mag
end
def +(other)
result = other.to_serial
result.value += value
return result
end
def -(other)
result = other.to_serial
result.value = value - result.value
return result
end
def succ
Serial.new(value + 1)
end
# FIXME: Not sure what to do here
# Ruby doesn't have a notion of a evaluable string representation
# def __repr__(self):
# return "serial(%s)" % self.value
# end
def to_s
value.to_s
end
end
# The Python class datatypes.Range is emulated by the standard
# Range class with a few additions
class ::Range
alias :lower :begin
alias :upper :end
def touches(r)
# XXX: are we doing more checks than we need?
return (r.include?(lower - 1) ||
r.include?(upper + 1) ||
include?(r.lower - 1) ||
include?(r.upper + 1) ||
r.include?(lower) ||
r.include?(upper) ||
include?(r.lower) ||
include?(r.upper))
end
def span(r)
Range.new([lower, r.lower].min, [upper, r.upper].max)
end
def intersect(r)
l = [lower, r.lower].max
u = [upper, r.upper].min
return l > u ? nil : Range.new(l, u)
end
end
class RangedSet
include Enumerable
attr_accessor :ranges
def initialize(*args)
@ranges = []
args.each { |n| add(n) }
end
def each(&block)
ranges.each { |r| yield(r) }
end
def include?(n)
if (n.is_a?(Range))
super(n)
else
ranges.find { |r| r.include?(n) }
end
end
def add_range(range)
ranges.delete_if do |r|
if range.touches(r)
range = range.span(r)
true
else
false
end
end
ranges << range
end
def add(lower, upper = nil)
upper = lower if upper.nil?
add_range(Range.new(lower, upper))
end
def to_s
repr = ranges.sort { |a,b| b.lower <=> a.lower }.
map { |r| r.to_s }.join(",")
"<RangedSet: {#{repr}}"
end
end
class Future
def initialize(initial=nil, exception=Exception)
@value = initial
@error = nil
@set = Util::Event.new
@exception = exception
end
def error(error)
@error = error
@set.set
end
def set(value)
@value = value
@set.set
end
def get(timeout=nil)
@set.wait(timeout)
unless @error.nil?
raise @exception.new(@error)
end
@value
end
end
class UUID
include Comparable
attr_accessor :bytes
def initialize(bytes)
@bytes = bytes
end
def <=>(other)
if other.respond_to?(:bytes)
return bytes <=> other.bytes
else
raise NotImplementedError
end
end
def to_s
UUID::format(bytes)
end
# FIXME: Not sure what to do here
# Ruby doesn't have a notion of a evaluable string representation
# def __repr__(self):
# return "UUID(%r)" % str(self)
# end
def self.random_uuid
bytes = (1..16).collect { |i| rand(256) }
# From RFC4122, the version bits are set to 0100
bytes[7] &= 0x0F
bytes[7] |= 0x40
# From RFC4122, the top two bits of byte 8 get set to 01
bytes[8] &= 0x3F
bytes[8] |= 0x80
return bytes.pack("C16")
end
def self.uuid4
UUID.new(random_uuid)
end
def self.format(s)
# Python format !LHHHHL
# big-endian, ulong, ushort x 4, ulong
"%08x-%04x-%04x-%04x-%04x%08x" % s.unpack("NnnnnN")
end
end
end