blob: c36c1610eea6945993a79e3fc025cbdf8aa5d23e [file] [log] [blame]
Kevin Clark916f3532009-03-20 04:21:39 +00001/**
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
Bryan Duxbury09d13c22010-08-11 18:37:25 +000020#include "struct.h"
21#include "constants.h"
Bryan Duxbury6b771d22009-03-26 04:55:34 +000022#include "macros.h"
Jake Farrelld5df77a2011-11-06 17:43:44 +000023#include "strlcpy.h"
Bryan Duxburyc0166282009-02-02 00:48:17 +000024
Bryan Duxbury33e190c2010-02-16 21:19:01 +000025VALUE thrift_union_class;
26
27ID setfield_id;
28ID setvalue_id;
29
30ID to_s_method_id;
31ID name_to_id_method_id;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +000032static ID sorted_field_ids_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000033
34#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
35#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
36
37//-------------------------------------------
38// Writing section
39//-------------------------------------------
40
41// default fn pointers for protocol stuff here
42
43VALUE default_write_bool(VALUE protocol, VALUE value) {
44 rb_funcall(protocol, write_boolean_method_id, 1, value);
45 return Qnil;
46}
47
48VALUE default_write_byte(VALUE protocol, VALUE value) {
49 rb_funcall(protocol, write_byte_method_id, 1, value);
50 return Qnil;
51}
52
53VALUE default_write_i16(VALUE protocol, VALUE value) {
54 rb_funcall(protocol, write_i16_method_id, 1, value);
55 return Qnil;
56}
57
58VALUE default_write_i32(VALUE protocol, VALUE value) {
59 rb_funcall(protocol, write_i32_method_id, 1, value);
60 return Qnil;
61}
62
63VALUE default_write_i64(VALUE protocol, VALUE value) {
64 rb_funcall(protocol, write_i64_method_id, 1, value);
65 return Qnil;
66}
67
68VALUE default_write_double(VALUE protocol, VALUE value) {
69 rb_funcall(protocol, write_double_method_id, 1, value);
70 return Qnil;
71}
72
73VALUE default_write_string(VALUE protocol, VALUE value) {
74 rb_funcall(protocol, write_string_method_id, 1, value);
75 return Qnil;
76}
77
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -050078VALUE default_write_uuid(VALUE protocol, VALUE value) {
79 rb_funcall(protocol, write_uuid_method_id, 1, value);
80 return Qnil;
81}
82
henrique8a2bab32014-07-16 20:10:57 +020083VALUE default_write_binary(VALUE protocol, VALUE value) {
84 rb_funcall(protocol, write_binary_method_id, 1, value);
85 return Qnil;
86}
87
Bryan Duxburyc0166282009-02-02 00:48:17 +000088VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
89 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
90 return Qnil;
91}
92
93VALUE default_write_list_end(VALUE protocol) {
94 rb_funcall(protocol, write_list_end_method_id, 0);
95 return Qnil;
96}
97
98VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
99 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
100 return Qnil;
101}
102
103VALUE default_write_set_end(VALUE protocol) {
104 rb_funcall(protocol, write_set_end_method_id, 0);
105 return Qnil;
106}
107
108VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
109 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
110 return Qnil;
111}
112
113VALUE default_write_map_end(VALUE protocol) {
114 rb_funcall(protocol, write_map_end_method_id, 0);
115 return Qnil;
116}
117
118VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
119 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
120 return Qnil;
121}
122
123VALUE default_write_struct_end(VALUE protocol) {
124 rb_funcall(protocol, write_struct_end_method_id, 0);
125 return Qnil;
126}
127
128VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
129 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
130 return Qnil;
131}
132
133VALUE default_write_field_end(VALUE protocol) {
134 rb_funcall(protocol, write_field_end_method_id, 0);
135 return Qnil;
136}
137
138VALUE default_write_field_stop(VALUE protocol) {
139 rb_funcall(protocol, write_field_stop_method_id, 0);
140 return Qnil;
141}
142
143VALUE default_read_field_begin(VALUE protocol) {
144 return rb_funcall(protocol, read_field_begin_method_id, 0);
145}
146
147VALUE default_read_field_end(VALUE protocol) {
148 return rb_funcall(protocol, read_field_end_method_id, 0);
149}
150
151VALUE default_read_map_begin(VALUE protocol) {
152 return rb_funcall(protocol, read_map_begin_method_id, 0);
153}
154
155VALUE default_read_map_end(VALUE protocol) {
156 return rb_funcall(protocol, read_map_end_method_id, 0);
157}
158
159VALUE default_read_list_begin(VALUE protocol) {
160 return rb_funcall(protocol, read_list_begin_method_id, 0);
161}
162
163VALUE default_read_list_end(VALUE protocol) {
164 return rb_funcall(protocol, read_list_end_method_id, 0);
165}
166
167VALUE default_read_set_begin(VALUE protocol) {
168 return rb_funcall(protocol, read_set_begin_method_id, 0);
169}
170
171VALUE default_read_set_end(VALUE protocol) {
172 return rb_funcall(protocol, read_set_end_method_id, 0);
173}
174
175VALUE default_read_byte(VALUE protocol) {
176 return rb_funcall(protocol, read_byte_method_id, 0);
177}
178
179VALUE default_read_bool(VALUE protocol) {
180 return rb_funcall(protocol, read_bool_method_id, 0);
181}
182
183VALUE default_read_i16(VALUE protocol) {
184 return rb_funcall(protocol, read_i16_method_id, 0);
185}
186
187VALUE default_read_i32(VALUE protocol) {
188 return rb_funcall(protocol, read_i32_method_id, 0);
189}
190
191VALUE default_read_i64(VALUE protocol) {
192 return rb_funcall(protocol, read_i64_method_id, 0);
193}
194
195VALUE default_read_double(VALUE protocol) {
196 return rb_funcall(protocol, read_double_method_id, 0);
197}
198
199VALUE default_read_string(VALUE protocol) {
200 return rb_funcall(protocol, read_string_method_id, 0);
201}
202
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500203VALUE default_read_uuid(VALUE protocol) {
204 return rb_funcall(protocol, read_uuid_method_id, 0);
205}
206
henrique8a2bab32014-07-16 20:10:57 +0200207VALUE default_read_binary(VALUE protocol) {
208 return rb_funcall(protocol, read_binary_method_id, 0);
209}
210
Bryan Duxburyc0166282009-02-02 00:48:17 +0000211VALUE default_read_struct_begin(VALUE protocol) {
212 return rb_funcall(protocol, read_struct_begin_method_id, 0);
213}
214
215VALUE default_read_struct_end(VALUE protocol) {
216 return rb_funcall(protocol, read_struct_end_method_id, 0);
217}
218
Bryan Duxburyc0166282009-02-02 00:48:17 +0000219// end default protocol methods
220
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000221static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000222static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
223static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
224
225VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000226 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000227
Bryan Duxburyc0166282009-02-02 00:48:17 +0000228 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000229 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000230
231 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000232
Bryan Duxburyc0166282009-02-02 00:48:17 +0000233 return value;
234}
235
236static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
Jean Boussier1e843412021-10-13 12:36:28 +0200237 long sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000238
Bryan Duxburyc0166282009-02-02 00:48:17 +0000239 if (ttype == TTYPE_MAP) {
240 VALUE keys;
241 VALUE key;
242 VALUE val;
243
244 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000245
Bryan Duxburyc0166282009-02-02 00:48:17 +0000246 VALUE key_info = rb_hash_aref(field_info, key_sym);
247 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
248 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000249
Bryan Duxburyc0166282009-02-02 00:48:17 +0000250 VALUE value_info = rb_hash_aref(field_info, value_sym);
251 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
252 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000253
Bryan Duxburyc0166282009-02-02 00:48:17 +0000254 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000255
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000256 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000257
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000258 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000259
Bryan Duxburyc0166282009-02-02 00:48:17 +0000260 for (i = 0; i < sz; i++) {
261 key = rb_ary_entry(keys, i);
262 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000263
Bryan Duxburyc0166282009-02-02 00:48:17 +0000264 if (IS_CONTAINER(keytype)) {
265 write_container(keytype, key_info, key, protocol);
266 } else {
267 write_anything(keytype, key, protocol, key_info);
268 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000269
Bryan Duxburyc0166282009-02-02 00:48:17 +0000270 if (IS_CONTAINER(valuetype)) {
271 write_container(valuetype, value_info, val, protocol);
272 } else {
273 write_anything(valuetype, val, protocol, value_info);
274 }
275 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000276
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000277 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000278 } else if (ttype == TTYPE_LIST) {
279 Check_Type(value, T_ARRAY);
280
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000281 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000282
283 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
284 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
285 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000286
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000287 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000288 for (i = 0; i < sz; ++i) {
289 VALUE val = rb_ary_entry(value, i);
290 if (IS_CONTAINER(element_type)) {
291 write_container(element_type, element_type_info, val, protocol);
292 } else {
293 write_anything(element_type, val, protocol, element_type_info);
294 }
295 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000296 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000297 } else if (ttype == TTYPE_SET) {
298 VALUE items;
299
300 if (TYPE(value) == T_ARRAY) {
301 items = value;
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000302 } else {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000303 if (rb_cSet == CLASS_OF(value)) {
304 items = rb_funcall(value, entries_method_id, 0);
305 } else {
306 Check_Type(value, T_HASH);
307 items = rb_funcall(value, keys_method_id, 0);
308 }
309 }
310
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000311 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000312
313 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
314 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
315 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000316
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000317 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000318
Bryan Duxburyc0166282009-02-02 00:48:17 +0000319 for (i = 0; i < sz; i++) {
320 VALUE val = rb_ary_entry(items, i);
321 if (IS_CONTAINER(element_type)) {
322 write_container(element_type, element_type_info, val, protocol);
323 } else {
324 write_anything(element_type, val, protocol, element_type_info);
325 }
326 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000327
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000328 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000329 } else {
330 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
331 }
332}
333
334static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
335 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000336 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000337 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000338 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000339 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000340 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000341 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000342 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000343 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000344 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000345 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000346 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000347 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200348 VALUE is_binary = rb_hash_aref(field_info, binary_sym);
349 if (is_binary != Qtrue) {
350 default_write_string(protocol, value);
351 } else {
352 default_write_binary(protocol, value);
353 }
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500354 } else if (ttype == TTYPE_UUID) {
355 default_write_uuid(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000356 } else if (IS_CONTAINER(ttype)) {
357 write_container(ttype, field_info, value, protocol);
358 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000359 if (rb_obj_is_kind_of(value, thrift_union_class)) {
360 rb_thrift_union_write(value, protocol);
361 } else {
362 rb_thrift_struct_write(value, protocol);
363 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000364 } else {
365 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
366 }
367}
368
369static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
370 // call validate
371 rb_funcall(self, validate_method_id, 0);
372
Bryan Duxburyc0166282009-02-02 00:48:17 +0000373 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000374 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000375
Bryan Duxburyc0166282009-02-02 00:48:17 +0000376 // iterate through all the fields here
377 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000378 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000379
Bryan Duxburyc0166282009-02-02 00:48:17 +0000380 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000381 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
382 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000383
Bryan Duxburyc0166282009-02-02 00:48:17 +0000384 VALUE field_info = rb_hash_aref(struct_fields, field_id);
385
386 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
387 int ttype = FIX2INT(ttype_value);
388 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000389
Bryan Duxburyc0166282009-02-02 00:48:17 +0000390 VALUE field_value = get_field_value(self, field_name);
391
392 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000393 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000394
Bryan Duxburyc0166282009-02-02 00:48:17 +0000395 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000396
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000397 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000398 }
399 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000400
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000401 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000402
Bryan Duxburyc0166282009-02-02 00:48:17 +0000403 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000404 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000405
Bryan Duxburyc0166282009-02-02 00:48:17 +0000406 return Qnil;
407}
408
409//-------------------------------------------
410// Reading section
411//-------------------------------------------
412
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000413static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000414static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000415static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
416static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000417
418static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000419 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000420
421 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000422 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000423
424 rb_ivar_set(obj, rb_intern(name_buf), value);
425}
426
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000427// Helper method to skip the contents of a map (assumes the map header has been read).
428static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
429 int i;
430 for (i = 0; i < size; i++) {
431 rb_funcall(protocol, skip_method_id, 1, key_type_value);
432 rb_funcall(protocol, skip_method_id, 1, value_type_value);
433 }
434}
435
436// Helper method to skip the contents of a list or set (assumes the list/set header has been read).
437static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
438 int i;
439 for (i = 0; i < size; i++) {
440 rb_funcall(protocol, skip_method_id, 1, element_type_value);
441 }
442}
443
Bryan Duxburyc0166282009-02-02 00:48:17 +0000444static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
445 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000446
Bryan Duxburyc0166282009-02-02 00:48:17 +0000447 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000448 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000449 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000450 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000451 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000452 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000453 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000454 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000455 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000456 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000457 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200458 VALUE is_binary = rb_hash_aref(field_info, binary_sym);
459 if (is_binary != Qtrue) {
460 result = default_read_string(protocol);
461 } else {
462 result = default_read_binary(protocol);
463 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000464 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000465 result = default_read_double(protocol);
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500466 } else if (ttype == TTYPE_UUID) {
467 result = default_read_uuid(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000468 } else if (ttype == TTYPE_STRUCT) {
469 VALUE klass = rb_hash_aref(field_info, class_sym);
470 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000471
472 if (rb_obj_is_kind_of(result, thrift_union_class)) {
473 rb_thrift_union_read(result, protocol);
474 } else {
475 rb_thrift_struct_read(result, protocol);
476 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000477 } else if (ttype == TTYPE_MAP) {
478 int i;
479
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000480 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000481 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
482 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
483 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000484
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000485 // Check the declared key and value types against the expected ones and skip the map contents
486 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000487 VALUE key_info = rb_hash_aref(field_info, key_sym);
488 VALUE value_info = rb_hash_aref(field_info, value_sym);
489
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000490 if (!NIL_P(key_info) && !NIL_P(value_info)) {
491 int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
492 int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000493 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000494 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000495
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000496 for (i = 0; i < num_entries; ++i) {
497 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000498
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000499 key = read_anything(protocol, key_ttype, key_info);
500 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000501
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000502 rb_hash_aset(result, key, val);
503 }
504 } else {
505 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
506 }
507 } else {
508 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000509 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000510
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000511 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000512 } else if (ttype == TTYPE_LIST) {
513 int i;
514
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000515 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000516 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
517 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000518
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000519 // Check the declared element type against the expected one and skip the list contents
520 // if the types don't match.
521 VALUE element_info = rb_hash_aref(field_info, element_sym);
522 if (!NIL_P(element_info)) {
523 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
524 if (specified_element_type == element_ttype) {
525 result = rb_ary_new2(num_elements);
526
527 for (i = 0; i < num_elements; ++i) {
528 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
529 }
530 } else {
531 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
532 }
533 } else {
534 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000535 }
536
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000537 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000538 } else if (ttype == TTYPE_SET) {
539 VALUE items;
540 int i;
541
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000542 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000543 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
544 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000545
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000546 // Check the declared element type against the expected one and skip the set contents
547 // if the types don't match.
548 VALUE element_info = rb_hash_aref(field_info, element_sym);
549 if (!NIL_P(element_info)) {
550 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
551 if (specified_element_type == element_ttype) {
552 items = rb_ary_new2(num_elements);
553
554 for (i = 0; i < num_elements; ++i) {
555 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
556 }
557
558 result = rb_class_new_instance(1, &items, rb_cSet);
559 } else {
560 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
561 }
562 } else {
563 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000564 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000565
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000566 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000567 } else {
568 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
569 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000570
Bryan Duxburyc0166282009-02-02 00:48:17 +0000571 return result;
572}
573
574static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000575 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000576 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000577
578 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000579
Bryan Duxburyc0166282009-02-02 00:48:17 +0000580 // read each field
581 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000582 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000583 VALUE field_type_value = rb_ary_entry(field_header, 1);
584 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000585
Bryan Duxburyc0166282009-02-02 00:48:17 +0000586 if (field_type == TTYPE_STOP) {
587 break;
588 }
589
590 // make sure we got a type we expected
591 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
592
593 if (!NIL_P(field_info)) {
594 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
595 if (field_type == specified_type) {
596 // read the value
597 VALUE name = rb_hash_aref(field_info, name_sym);
598 set_field_value(self, name, read_anything(protocol, field_type, field_info));
599 } else {
600 rb_funcall(protocol, skip_method_id, 1, field_type_value);
601 }
602 } else {
603 rb_funcall(protocol, skip_method_id, 1, field_type_value);
604 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000605
Bryan Duxburyc0166282009-02-02 00:48:17 +0000606 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000607 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000608 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000609
Bryan Duxburyc0166282009-02-02 00:48:17 +0000610 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000611 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000612
Bryan Duxbury834895d2009-10-15 01:20:34 +0000613 // call validate
614 rb_funcall(self, validate_method_id, 0);
615
Bryan Duxburyc0166282009-02-02 00:48:17 +0000616 return Qnil;
617}
618
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000619
620// --------------------------------
621// Union section
622// --------------------------------
623
624static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
625 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000626 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000627
628 VALUE struct_fields = STRUCT_FIELDS(self);
629
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000630 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000631 VALUE field_type_value = rb_ary_entry(field_header, 1);
632 int field_type = FIX2INT(field_type_value);
633
634 // make sure we got a type we expected
635 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
636
637 if (!NIL_P(field_info)) {
638 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
639 if (field_type == specified_type) {
640 // read the value
641 VALUE name = rb_hash_aref(field_info, name_sym);
Roger Meier02405722014-01-12 23:29:11 +0100642 rb_iv_set(self, "@setfield", rb_str_intern(name));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000643 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
644 } else {
645 rb_funcall(protocol, skip_method_id, 1, field_type_value);
646 }
647 } else {
648 rb_funcall(protocol, skip_method_id, 1, field_type_value);
649 }
650
651 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000652 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000653
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000654 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000655 field_type_value = rb_ary_entry(field_header, 1);
656 field_type = FIX2INT(field_type_value);
657
658 if (field_type != TTYPE_STOP) {
659 rb_raise(rb_eRuntimeError, "too many fields in union!");
660 }
661
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000662 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000663 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000664
665 // call validate
666 rb_funcall(self, validate_method_id, 0);
667
668 return Qnil;
669}
670
671static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
672 // call validate
673 rb_funcall(self, validate_method_id, 0);
674
675 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000676 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000677
678 VALUE struct_fields = STRUCT_FIELDS(self);
679
680 VALUE setfield = rb_ivar_get(self, setfield_id);
681 VALUE setvalue = rb_ivar_get(self, setvalue_id);
682 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
683
684 VALUE field_info = rb_hash_aref(struct_fields, field_id);
685
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000686 if(NIL_P(field_info)) {
687 rb_raise(rb_eRuntimeError, "set_field is not valid for this union!");
688 }
689
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000690 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
691 int ttype = FIX2INT(ttype_value);
692
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000693 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000694
695 write_anything(ttype, setvalue, protocol, field_info);
696
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000697 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000698
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000699 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000700
701 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000702 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000703
704 return Qnil;
705}
706
Dmytro Shteflyuk0d18fb22025-12-20 12:13:46 -0500707void Init_struct(void) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000708 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000709
Bryan Duxburyc0166282009-02-02 00:48:17 +0000710 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
711 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000712
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000713 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
Stan Hucc70b4e2021-03-11 03:49:57 +0530714 rb_global_variable(&thrift_union_class);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000715
716 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
717 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
718
719 setfield_id = rb_intern("@setfield");
Stan Hucc70b4e2021-03-11 03:49:57 +0530720 rb_global_variable(&setfield_id);
721
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000722 setvalue_id = rb_intern("@value");
Stan Hucc70b4e2021-03-11 03:49:57 +0530723 rb_global_variable(&setvalue_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000724
725 to_s_method_id = rb_intern("to_s");
Stan Hucc70b4e2021-03-11 03:49:57 +0530726 rb_global_variable(&to_s_method_id);
727
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000728 name_to_id_method_id = rb_intern("name_to_id");
Stan Hucc70b4e2021-03-11 03:49:57 +0530729 rb_global_variable(&name_to_id_method_id);
730
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000731 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Stan Hucc70b4e2021-03-11 03:49:57 +0530732 rb_global_variable(&sorted_field_ids_method_id);
Bryan Duxbury65073e52010-02-23 15:46:46 +0000733}