File: wrapper.rb

package info (click to toggle)
qpid-proton 0.37.0-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,384 kB
  • sloc: ansic: 37,828; cpp: 37,140; python: 15,302; ruby: 6,018; xml: 477; sh: 320; pascal: 52; makefile: 18
file content (148 lines) | stat: -rw-r--r-- 5,787 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# 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::Proton
  module Util

    # @private
    # Class methods to help wrapper classes define forwarding methods to proton-C functions
    #
    # The extending class must define PROTON_METHOD_PREFIX, the functions here
    # make it easy to define ruby methods to forward calls to C functions.
    #
    module SWIGClassHelper
      # Define ruby method +name+ to forward arguments to
      # CProton.PROTON_METHOD_PREFIX_+pn_name+(@impl, ...)
      def proton_forward(name, pn_name)
        pn_name = pn_name[0..-2] if pn_name.to_s.end_with? "?" # Drop trailing ? for ruby bool methods
        pn_name = "#{self::PROTON_METHOD_PREFIX}_#{pn_name}".to_sym
        define_method(name.to_sym) { |*args| Cproton.__send__(pn_name, @impl, *args) }
      end

      def proton_caller(*names) names.each { |name| proton_forward(name, name) }; end
      def proton_set(*names) names.each { |name| proton_forward("#{name}=", "set_#{name}") }; end
      def proton_get(*names) names.each { |name| proton_forward(name, "get_#{name}") }; end
      def proton_is(*names) names.each { |name| proton_forward("#{name}?", "is_#{name}") }; end
      def proton_set_get(*names) names.each { |name| proton_get(name); proton_set(name) }; end
      def proton_set_is(*names) names.each { |name| proton_is(name); proton_set(name) }; end

      # Store ruby wrappers as attachments so they can be retrieved from the C pointer.
      #
      # Wrappers are stored in a registry using a key. The key is then attached to
      # the Proton structure as a record. That record lives for as long as the
      # Proton structure lives, and when the structure is released the record acts
      # as hook to also delete the Ruby wrapper object from the registry.

      @@registry = {}

      # @private
      def get_key(impl)
        ("%032x" % Cproton.pni_address_of(impl))
      end

      # @private
      # Stores the given object for later retrieval.
      #
      # @param object [Object] The object.
      # @param attachment_method [Symbol] The Proton attachment method.
      #
      def store_instance(object, attachment_method = nil)
        # ensure the impl has a reference to the wrapper object
        object.impl.instance_eval { @proton_wrapper = object }
        registry_key = get_key(object.impl)
        unless attachment_method.nil?
          record = Cproton.__send__(attachment_method, object.impl)
          rbkey = Cproton.Pn_rbkey_new
          Cproton.Pn_rbkey_set_registry(rbkey, Cproton.pn_rb2void(Qpid::Proton::Util::Wrapper.registry))
          Cproton.Pn_rbkey_set_method(rbkey, "delete")
          Cproton.Pn_rbkey_set_key_value(rbkey, registry_key)
          Cproton.pn_record_def(record, RBCTX, Cproton.Pn_rbkey__class());
          Cproton.pn_record_set(record, RBCTX, rbkey)
        end
        @@registry[registry_key] = object
      end

      # Retrieves the wrapper object with the supplied Proton struct.
      #
      # @param impl [Object] The wrapper for the Proton struct.
      # @param attachment_method [Symbol] The Proton attachment method.
      #
      # @return [Object] The Ruby wrapper object.
      #
      def fetch_instance(impl, attachment_method = nil)
        # if the impl has a wrapper already attached, then return it
        if impl.instance_variable_defined?(:@proton_wrapper)
          return impl.instance_variable_get(:@proton_wrapper)
        end
        unless attachment_method.nil?
          record = Cproton.__send__(attachment_method, impl)
          rbkey = Cproton.pni_void2rbkey(Cproton.pn_record_get(record, RBCTX))
          # if we don't have a key, then we don't have an object
          return nil if rbkey.nil?
          registry_key = Cproton.Pn_rbkey_get_key_value(rbkey)
        else
          registry_key = get_key(impl)
        end
        # if the object's not in the registry then return
        return nil unless @@registry.has_key?(registry_key)

        result = @@registry[registry_key]
        # result = nil unless result.weakref_alive?
        if result.nil?
          raise Qpid::Proton::ProtonError.new("missing object for key=#{registry_key}")
        else
          # update the impl since the Swig wrapper for it may have changed
          result.impl = impl
        end
        return result
      end
      RBCTX = self.hash.to_i
    end

    # @private
    #
    # Instance methods to include in classes that wrap pn_object types
    # that support pn_inspect etc. Automatically extends SWIGClassHelper
    #
    module Wrapper

      def self.included(base)
        base.extend(SWIGClassHelper)
      end

      attr_accessor :impl

      def inspect
        return "#{self.class}<nil>" unless @impl
        pstr = Cproton.pn_string("")
        begin
          Cproton.pn_inspect(@impl, pstr)
          return Cproton.pn_string_get(pstr)
        ensure
          Cproton.pn_free(pstr)
        end
      end

      def to_s() inspect; end

      def self.registry
        @registry ||= {}
      end
    end
  end
end