]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/rb/lib/thrift/struct.rb
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / rb / lib / thrift / struct.rb
1 #
2 # Licensed to the Apache Software Foundation (ASF) under one
3 # or more contributor license agreements. See the NOTICE file
4 # distributed with this work for additional information
5 # regarding copyright ownership. The ASF licenses this file
6 # to you under the Apache License, Version 2.0 (the
7 # "License"); you may not use this file except in compliance
8 # with the License. You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing,
13 # software distributed under the License is distributed on an
14 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 # KIND, either express or implied. See the License for the
16 # specific language governing permissions and limitations
17 # under the License.
18 #
19
20 require 'set'
21
22 module Thrift
23 module Struct
24 def initialize(d={}, &block)
25 # get a copy of the default values to work on, removing defaults in favor of arguments
26 fields_with_defaults = fields_with_default_values.dup
27
28 # check if the defaults is empty, or if there are no parameters for this
29 # instantiation, and if so, don't bother overriding defaults.
30 unless fields_with_defaults.empty? || d.empty?
31 d.each_key do |name|
32 fields_with_defaults.delete(name.to_s)
33 end
34 end
35
36 # assign all the user-specified arguments
37 unless d.empty?
38 d.each do |name, value|
39 unless name_to_id(name.to_s)
40 raise Exception, "Unknown key given to #{self.class}.new: #{name}"
41 end
42 Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking
43 instance_variable_set("@#{name}", value)
44 end
45 end
46
47 # assign all the default values
48 unless fields_with_defaults.empty?
49 fields_with_defaults.each do |name, default_value|
50 instance_variable_set("@#{name}", (default_value.dup rescue default_value))
51 end
52 end
53
54 yield self if block_given?
55 end
56
57 def fields_with_default_values
58 fields_with_default_values = self.class.instance_variable_get(:@fields_with_default_values)
59 unless fields_with_default_values
60 fields_with_default_values = {}
61 struct_fields.each do |fid, field_def|
62 unless field_def[:default].nil?
63 fields_with_default_values[field_def[:name]] = field_def[:default]
64 end
65 end
66 self.class.instance_variable_set(:@fields_with_default_values, fields_with_default_values)
67 end
68 fields_with_default_values
69 end
70
71 def inspect(skip_optional_nulls = true)
72 fields = []
73 each_field do |fid, field_info|
74 name = field_info[:name]
75 value = instance_variable_get("@#{name}")
76 unless skip_optional_nulls && field_info[:optional] && value.nil?
77 fields << "#{name}:#{inspect_field(value, field_info)}"
78 end
79 end
80 "<#{self.class} #{fields.join(", ")}>"
81 end
82
83 def read(iprot)
84 iprot.read_struct_begin
85 loop do
86 fname, ftype, fid = iprot.read_field_begin
87 break if (ftype == Types::STOP)
88 handle_message(iprot, fid, ftype)
89 iprot.read_field_end
90 end
91 iprot.read_struct_end
92 validate
93 end
94
95 def write(oprot)
96 validate
97 oprot.write_struct_begin(self.class.name)
98 each_field do |fid, field_info|
99 name = field_info[:name]
100 type = field_info[:type]
101 value = instance_variable_get("@#{name}")
102 unless value.nil?
103 if is_container? type
104 oprot.write_field_begin(name, type, fid)
105 write_container(oprot, value, field_info)
106 oprot.write_field_end
107 else
108 oprot.write_field(field_info, fid, value)
109 end
110 end
111 end
112 oprot.write_field_stop
113 oprot.write_struct_end
114 end
115
116 def ==(other)
117 return false if other.nil?
118 each_field do |fid, field_info|
119 name = field_info[:name]
120 return false unless other.respond_to?(name) && self.send(name) == other.send(name)
121 end
122 true
123 end
124
125 def eql?(other)
126 self.class == other.class && self == other
127 end
128
129 # This implementation of hash() is inspired by Apache's Java HashCodeBuilder class.
130 def hash
131 total = 17
132 each_field do |fid, field_info|
133 name = field_info[:name]
134 value = self.send(name)
135 total = (total * 37 + value.hash) & 0xffffffff
136 end
137 total
138 end
139
140 def differences(other)
141 diffs = []
142 unless other.is_a?(self.class)
143 diffs << "Different class!"
144 else
145 each_field do |fid, field_info|
146 name = field_info[:name]
147 diffs << "#{name} differs!" unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")
148 end
149 end
150 diffs
151 end
152
153 def self.field_accessor(klass, field_info)
154 field_name_sym = field_info[:name].to_sym
155 klass.send :attr_reader, field_name_sym
156 klass.send :define_method, "#{field_info[:name]}=" do |value|
157 Thrift.check_type(value, field_info, field_info[:name]) if Thrift.type_checking
158 instance_variable_set("@#{field_name_sym}", value)
159 end
160 end
161
162 def self.generate_accessors(klass)
163 klass::FIELDS.values.each do |field_info|
164 field_accessor(klass, field_info)
165 qmark_isset_method(klass, field_info)
166 end
167 end
168
169 def self.qmark_isset_method(klass, field_info)
170 klass.send :define_method, "#{field_info[:name]}?" do
171 !self.send(field_info[:name].to_sym).nil?
172 end
173 end
174
175 def <=>(other)
176 if self.class == other.class
177 each_field do |fid, field_info|
178 v1 = self.send(field_info[:name])
179 v1_set = !v1.nil?
180 v2 = other.send(field_info[:name])
181 v2_set = !v2.nil?
182 if v1_set && !v2_set
183 return -1
184 elsif !v1_set && v2_set
185 return 1
186 elsif v1_set && v2_set
187 cmp = v1 <=> v2
188 if cmp != 0
189 return cmp
190 end
191 end
192 end
193 0
194 else
195 self.class <=> other.class
196 end
197 end
198
199 protected
200
201 def self.append_features(mod)
202 if mod.ancestors.include? ::Exception
203 mod.send :class_variable_set, :'@@__thrift_struct_real_initialize', mod.instance_method(:initialize)
204 super
205 # set up our custom initializer so `raise Xception, 'message'` works
206 mod.send :define_method, :struct_initialize, mod.instance_method(:initialize)
207 mod.send :define_method, :initialize, mod.instance_method(:exception_initialize)
208 else
209 super
210 end
211 end
212
213 def exception_initialize(*args, &block)
214 if args.size == 1 and args.first.is_a? Hash
215 # looks like it's a regular Struct initialize
216 method(:struct_initialize).call(args.first)
217 else
218 # call the Struct initializer first with no args
219 # this will set our field default values
220 method(:struct_initialize).call()
221 # now give it to the exception
222 self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args, &block) if args.size > 0
223 # self.class.instance_method(:initialize).bind(self).call(*args, &block)
224 end
225 end
226
227 def handle_message(iprot, fid, ftype)
228 field = struct_fields[fid]
229 if field and field[:type] == ftype
230 value = read_field(iprot, field)
231 instance_variable_set("@#{field[:name]}", value)
232 else
233 iprot.skip(ftype)
234 end
235 end
236 end
237 end