diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2011-08-14 16:21:34 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2011-08-14 16:21:34 +0000 |
commit | d84a3a50dbb794c4383de7e5eca730ca602771e7 (patch) | |
tree | 7c6177573a2eedc172de2cbd8354ce7b4ea1e8fe /qpid/ruby/lib/qpid/datatypes.rb | |
parent | 0aba202a7e2483f04fc77bbe4faa88bb86fe5b9b (diff) | |
parent | 47551f3aa2dd46b8daeeb9683a668464203ffa06 (diff) | |
download | qpid-python-d84a3a50dbb794c4383de7e5eca730ca602771e7.tar.gz |
Create sandbox from correct revision
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rg-amqp-1-0-sandbox@1157557 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/ruby/lib/qpid/datatypes.rb')
-rw-r--r-- | qpid/ruby/lib/qpid/datatypes.rb | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/qpid/ruby/lib/qpid/datatypes.rb b/qpid/ruby/lib/qpid/datatypes.rb new file mode 100644 index 0000000000..418388c73a --- /dev/null +++ b/qpid/ruby/lib/qpid/datatypes.rb @@ -0,0 +1,353 @@ +# +# 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 |