]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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 | module Thrift | |
21 | class Union | |
22 | def initialize(name=nil, value=nil) | |
23 | if name | |
24 | if name.is_a? Hash | |
25 | if name.size > 1 | |
26 | raise "#{self.class} cannot be instantiated with more than one field!" | |
27 | end | |
28 | ||
29 | name, value = name.keys.first, name.values.first | |
30 | end | |
31 | ||
32 | if Thrift.type_checking | |
33 | raise Exception, "#{self.class} does not contain a field named #{name}!" unless name_to_id(name.to_s) | |
34 | end | |
35 | ||
36 | if value.nil? | |
37 | raise Exception, "Union #{self.class} cannot be instantiated with setfield and nil value!" | |
38 | end | |
39 | ||
40 | Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking | |
41 | elsif !value.nil? | |
42 | raise Exception, "Value provided, but no name!" | |
43 | end | |
44 | @setfield = name | |
45 | @value = value | |
46 | end | |
47 | ||
48 | def inspect | |
49 | if get_set_field | |
50 | "<#{self.class} #{@setfield}: #{inspect_field(@value, struct_fields[name_to_id(@setfield.to_s)])}>" | |
51 | else | |
52 | "<#{self.class} >" | |
53 | end | |
54 | end | |
55 | ||
56 | def read(iprot) | |
57 | iprot.read_struct_begin | |
58 | fname, ftype, fid = iprot.read_field_begin | |
59 | handle_message(iprot, fid, ftype) | |
60 | iprot.read_field_end | |
61 | ||
62 | fname, ftype, fid = iprot.read_field_begin | |
63 | raise "Too many fields for union" unless (ftype == Types::STOP) | |
64 | ||
65 | iprot.read_struct_end | |
66 | validate | |
67 | end | |
68 | ||
69 | def write(oprot) | |
70 | validate | |
71 | oprot.write_struct_begin(self.class.name) | |
72 | ||
73 | fid = self.name_to_id(@setfield.to_s) | |
74 | ||
75 | field_info = struct_fields[fid] | |
76 | type = field_info[:type] | |
77 | if is_container? type | |
78 | oprot.write_field_begin(@setfield, type, fid) | |
79 | write_container(oprot, @value, field_info) | |
80 | oprot.write_field_end | |
81 | else | |
82 | oprot.write_field(@setfield, type, fid, @value) | |
83 | end | |
84 | ||
85 | oprot.write_field_stop | |
86 | oprot.write_struct_end | |
87 | end | |
88 | ||
89 | def ==(other) | |
90 | other.equal?(self) || other.instance_of?(self.class) && @setfield == other.get_set_field && @value == other.get_value | |
91 | end | |
92 | alias_method :eql?, :== | |
93 | ||
94 | def hash | |
95 | [self.class.name, @setfield, @value].hash | |
96 | end | |
97 | ||
98 | def self.field_accessor(klass, field_info) | |
99 | klass.send :define_method, field_info[:name] do | |
100 | if field_info[:name].to_sym == @setfield | |
101 | @value | |
102 | else | |
103 | raise RuntimeError, "#{field_info[:name]} is not union's set field." | |
104 | end | |
105 | end | |
106 | ||
107 | klass.send :define_method, "#{field_info[:name]}=" do |value| | |
108 | Thrift.check_type(value, field_info, field_info[:name]) if Thrift.type_checking | |
109 | @setfield = field_info[:name].to_sym | |
110 | @value = value | |
111 | end | |
112 | end | |
113 | ||
114 | def self.qmark_isset_method(klass, field_info) | |
115 | klass.send :define_method, "#{field_info[:name]}?" do | |
116 | get_set_field == field_info[:name].to_sym && !get_value.nil? | |
117 | end | |
118 | end | |
119 | ||
120 | def self.generate_accessors(klass) | |
121 | klass::FIELDS.values.each do |field_info| | |
122 | field_accessor(klass, field_info) | |
123 | qmark_isset_method(klass, field_info) | |
124 | end | |
125 | end | |
126 | ||
127 | # get the symbol that indicates what the currently set field type is. | |
128 | def get_set_field | |
129 | @setfield | |
130 | end | |
131 | ||
132 | # get the current value of this union, regardless of what the set field is. | |
133 | # generally, you should only use this method when you don't know in advance | |
134 | # what field to expect. | |
135 | def get_value | |
136 | @value | |
137 | end | |
138 | ||
139 | def <=>(other) | |
140 | if self.class == other.class | |
141 | if get_set_field == other.get_set_field | |
142 | if get_set_field.nil? | |
143 | 0 | |
144 | else | |
145 | get_value <=> other.get_value | |
146 | end | |
147 | else | |
148 | if get_set_field && other.get_set_field.nil? | |
149 | -1 | |
150 | elsif get_set_field.nil? && other.get_set_field | |
151 | 1 | |
152 | elsif get_set_field.nil? && other.get_set_field.nil? | |
153 | 0 | |
154 | else | |
155 | name_to_id(get_set_field.to_s) <=> name_to_id(other.get_set_field.to_s) | |
156 | end | |
157 | end | |
158 | else | |
159 | self.class <=> other.class | |
160 | end | |
161 | end | |
162 | ||
163 | protected | |
164 | ||
165 | def handle_message(iprot, fid, ftype) | |
166 | field = struct_fields[fid] | |
167 | if field and field[:type] == ftype | |
168 | @value = read_field(iprot, field) | |
169 | name = field[:name].to_sym | |
170 | @setfield = name | |
171 | else | |
172 | iprot.skip(ftype) | |
173 | end | |
174 | end | |
175 | end | |
176 | end |