blob: b61b995b185582c196c614790f4ca0015aa89400 [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"
Dmytro Shteflyuk32776c02026-02-10 12:25:07 -050023#include "protocol.h"
Jake Farrelld5df77a2011-11-06 17:43:44 +000024#include "strlcpy.h"
Bryan Duxburyc0166282009-02-02 00:48:17 +000025
Bryan Duxbury33e190c2010-02-16 21:19:01 +000026VALUE thrift_union_class;
27
28ID setfield_id;
29ID setvalue_id;
30
31ID to_s_method_id;
32ID name_to_id_method_id;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +000033static ID sorted_field_ids_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000034
35#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
36#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
37
38//-------------------------------------------
39// Writing section
40//-------------------------------------------
41
42// default fn pointers for protocol stuff here
43
44VALUE default_write_bool(VALUE protocol, VALUE value) {
45 rb_funcall(protocol, write_boolean_method_id, 1, value);
46 return Qnil;
47}
48
49VALUE default_write_byte(VALUE protocol, VALUE value) {
50 rb_funcall(protocol, write_byte_method_id, 1, value);
51 return Qnil;
52}
53
54VALUE default_write_i16(VALUE protocol, VALUE value) {
55 rb_funcall(protocol, write_i16_method_id, 1, value);
56 return Qnil;
57}
58
59VALUE default_write_i32(VALUE protocol, VALUE value) {
60 rb_funcall(protocol, write_i32_method_id, 1, value);
61 return Qnil;
62}
63
64VALUE default_write_i64(VALUE protocol, VALUE value) {
65 rb_funcall(protocol, write_i64_method_id, 1, value);
66 return Qnil;
67}
68
69VALUE default_write_double(VALUE protocol, VALUE value) {
70 rb_funcall(protocol, write_double_method_id, 1, value);
71 return Qnil;
72}
73
74VALUE default_write_string(VALUE protocol, VALUE value) {
75 rb_funcall(protocol, write_string_method_id, 1, value);
76 return Qnil;
77}
78
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -050079VALUE default_write_uuid(VALUE protocol, VALUE value) {
80 rb_funcall(protocol, write_uuid_method_id, 1, value);
81 return Qnil;
82}
83
henrique8a2bab32014-07-16 20:10:57 +020084VALUE default_write_binary(VALUE protocol, VALUE value) {
85 rb_funcall(protocol, write_binary_method_id, 1, value);
86 return Qnil;
87}
88
Bryan Duxburyc0166282009-02-02 00:48:17 +000089VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
90 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
91 return Qnil;
92}
93
94VALUE default_write_list_end(VALUE protocol) {
95 rb_funcall(protocol, write_list_end_method_id, 0);
96 return Qnil;
97}
98
99VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
100 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
101 return Qnil;
102}
103
104VALUE default_write_set_end(VALUE protocol) {
105 rb_funcall(protocol, write_set_end_method_id, 0);
106 return Qnil;
107}
108
109VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
110 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
111 return Qnil;
112}
113
114VALUE default_write_map_end(VALUE protocol) {
115 rb_funcall(protocol, write_map_end_method_id, 0);
116 return Qnil;
117}
118
119VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
120 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
121 return Qnil;
122}
123
124VALUE default_write_struct_end(VALUE protocol) {
125 rb_funcall(protocol, write_struct_end_method_id, 0);
126 return Qnil;
127}
128
129VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
130 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
131 return Qnil;
132}
133
134VALUE default_write_field_end(VALUE protocol) {
135 rb_funcall(protocol, write_field_end_method_id, 0);
136 return Qnil;
137}
138
139VALUE default_write_field_stop(VALUE protocol) {
140 rb_funcall(protocol, write_field_stop_method_id, 0);
141 return Qnil;
142}
143
144VALUE default_read_field_begin(VALUE protocol) {
145 return rb_funcall(protocol, read_field_begin_method_id, 0);
146}
147
148VALUE default_read_field_end(VALUE protocol) {
149 return rb_funcall(protocol, read_field_end_method_id, 0);
150}
151
152VALUE default_read_map_begin(VALUE protocol) {
153 return rb_funcall(protocol, read_map_begin_method_id, 0);
154}
155
156VALUE default_read_map_end(VALUE protocol) {
157 return rb_funcall(protocol, read_map_end_method_id, 0);
158}
159
160VALUE default_read_list_begin(VALUE protocol) {
161 return rb_funcall(protocol, read_list_begin_method_id, 0);
162}
163
164VALUE default_read_list_end(VALUE protocol) {
165 return rb_funcall(protocol, read_list_end_method_id, 0);
166}
167
168VALUE default_read_set_begin(VALUE protocol) {
169 return rb_funcall(protocol, read_set_begin_method_id, 0);
170}
171
172VALUE default_read_set_end(VALUE protocol) {
173 return rb_funcall(protocol, read_set_end_method_id, 0);
174}
175
176VALUE default_read_byte(VALUE protocol) {
177 return rb_funcall(protocol, read_byte_method_id, 0);
178}
179
180VALUE default_read_bool(VALUE protocol) {
181 return rb_funcall(protocol, read_bool_method_id, 0);
182}
183
184VALUE default_read_i16(VALUE protocol) {
185 return rb_funcall(protocol, read_i16_method_id, 0);
186}
187
188VALUE default_read_i32(VALUE protocol) {
189 return rb_funcall(protocol, read_i32_method_id, 0);
190}
191
192VALUE default_read_i64(VALUE protocol) {
193 return rb_funcall(protocol, read_i64_method_id, 0);
194}
195
196VALUE default_read_double(VALUE protocol) {
197 return rb_funcall(protocol, read_double_method_id, 0);
198}
199
200VALUE default_read_string(VALUE protocol) {
201 return rb_funcall(protocol, read_string_method_id, 0);
202}
203
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500204VALUE default_read_uuid(VALUE protocol) {
205 return rb_funcall(protocol, read_uuid_method_id, 0);
206}
207
henrique8a2bab32014-07-16 20:10:57 +0200208VALUE default_read_binary(VALUE protocol) {
209 return rb_funcall(protocol, read_binary_method_id, 0);
210}
211
Bryan Duxburyc0166282009-02-02 00:48:17 +0000212VALUE default_read_struct_begin(VALUE protocol) {
213 return rb_funcall(protocol, read_struct_begin_method_id, 0);
214}
215
216VALUE default_read_struct_end(VALUE protocol) {
217 return rb_funcall(protocol, read_struct_end_method_id, 0);
218}
219
Bryan Duxburyc0166282009-02-02 00:48:17 +0000220// end default protocol methods
221
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000222static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000223static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
224static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
225
226VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000227 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000228
Bryan Duxburyc0166282009-02-02 00:48:17 +0000229 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000230 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000231
232 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000233
Bryan Duxburyc0166282009-02-02 00:48:17 +0000234 return value;
235}
236
237static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
Jean Boussier1e843412021-10-13 12:36:28 +0200238 long sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000239
Bryan Duxburyc0166282009-02-02 00:48:17 +0000240 if (ttype == TTYPE_MAP) {
241 VALUE keys;
242 VALUE key;
243 VALUE val;
244
245 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000246
Bryan Duxburyc0166282009-02-02 00:48:17 +0000247 VALUE key_info = rb_hash_aref(field_info, key_sym);
248 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
249 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000250
Bryan Duxburyc0166282009-02-02 00:48:17 +0000251 VALUE value_info = rb_hash_aref(field_info, value_sym);
252 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
253 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000254
Bryan Duxburyc0166282009-02-02 00:48:17 +0000255 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000256
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000257 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000258
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000259 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000260
Bryan Duxburyc0166282009-02-02 00:48:17 +0000261 for (i = 0; i < sz; i++) {
262 key = rb_ary_entry(keys, i);
263 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000264
Bryan Duxburyc0166282009-02-02 00:48:17 +0000265 if (IS_CONTAINER(keytype)) {
266 write_container(keytype, key_info, key, protocol);
267 } else {
268 write_anything(keytype, key, protocol, key_info);
269 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000270
Bryan Duxburyc0166282009-02-02 00:48:17 +0000271 if (IS_CONTAINER(valuetype)) {
272 write_container(valuetype, value_info, val, protocol);
273 } else {
274 write_anything(valuetype, val, protocol, value_info);
275 }
276 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000277
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000278 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000279 } else if (ttype == TTYPE_LIST) {
280 Check_Type(value, T_ARRAY);
281
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000282 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000283
284 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
285 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
286 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000287
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000288 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000289 for (i = 0; i < sz; ++i) {
290 VALUE val = rb_ary_entry(value, i);
291 if (IS_CONTAINER(element_type)) {
292 write_container(element_type, element_type_info, val, protocol);
293 } else {
294 write_anything(element_type, val, protocol, element_type_info);
295 }
296 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000297 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000298 } else if (ttype == TTYPE_SET) {
299 VALUE items;
300
301 if (TYPE(value) == T_ARRAY) {
302 items = value;
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000303 } else {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000304 if (rb_cSet == CLASS_OF(value)) {
305 items = rb_funcall(value, entries_method_id, 0);
306 } else {
307 Check_Type(value, T_HASH);
308 items = rb_funcall(value, keys_method_id, 0);
309 }
310 }
311
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000312 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000313
314 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
315 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
316 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000317
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000318 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000319
Bryan Duxburyc0166282009-02-02 00:48:17 +0000320 for (i = 0; i < sz; i++) {
321 VALUE val = rb_ary_entry(items, i);
322 if (IS_CONTAINER(element_type)) {
323 write_container(element_type, element_type_info, val, protocol);
324 } else {
325 write_anything(element_type, val, protocol, element_type_info);
326 }
327 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000328
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000329 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000330 } else {
331 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
332 }
333}
334
335static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
336 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000337 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000338 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000339 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000340 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000341 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000342 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000343 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000344 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000345 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000346 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000347 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000348 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200349 VALUE is_binary = rb_hash_aref(field_info, binary_sym);
350 if (is_binary != Qtrue) {
351 default_write_string(protocol, value);
352 } else {
353 default_write_binary(protocol, value);
354 }
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500355 } else if (ttype == TTYPE_UUID) {
356 default_write_uuid(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000357 } else if (IS_CONTAINER(ttype)) {
358 write_container(ttype, field_info, value, protocol);
359 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000360 if (rb_obj_is_kind_of(value, thrift_union_class)) {
361 rb_thrift_union_write(value, protocol);
362 } else {
363 rb_thrift_struct_write(value, protocol);
364 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000365 } else {
366 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
367 }
368}
369
370static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
371 // call validate
372 rb_funcall(self, validate_method_id, 0);
373
Bryan Duxburyc0166282009-02-02 00:48:17 +0000374 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000375 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000376
Bryan Duxburyc0166282009-02-02 00:48:17 +0000377 // iterate through all the fields here
378 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000379 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000380
Bryan Duxburyc0166282009-02-02 00:48:17 +0000381 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000382 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
383 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000384
Bryan Duxburyc0166282009-02-02 00:48:17 +0000385 VALUE field_info = rb_hash_aref(struct_fields, field_id);
386
387 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
388 int ttype = FIX2INT(ttype_value);
389 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000390
Bryan Duxburyc0166282009-02-02 00:48:17 +0000391 VALUE field_value = get_field_value(self, field_name);
392
393 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000394 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000395
Bryan Duxburyc0166282009-02-02 00:48:17 +0000396 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000397
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000398 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000399 }
400 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000401
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000402 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000403
Bryan Duxburyc0166282009-02-02 00:48:17 +0000404 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000405 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000406
Bryan Duxburyc0166282009-02-02 00:48:17 +0000407 return Qnil;
408}
409
410//-------------------------------------------
411// Reading section
412//-------------------------------------------
413
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000414static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000415static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000416static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
417static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000418
419static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000420 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000421
422 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000423 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000424
425 rb_ivar_set(obj, rb_intern(name_buf), value);
426}
427
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000428// Helper method to skip the contents of a map (assumes the map header has been read).
429static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
430 int i;
431 for (i = 0; i < size; i++) {
432 rb_funcall(protocol, skip_method_id, 1, key_type_value);
433 rb_funcall(protocol, skip_method_id, 1, value_type_value);
434 }
435}
436
437// Helper method to skip the contents of a list or set (assumes the list/set header has been read).
438static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
439 int i;
440 for (i = 0; i < size; i++) {
441 rb_funcall(protocol, skip_method_id, 1, element_type_value);
442 }
443}
444
Bryan Duxburyc0166282009-02-02 00:48:17 +0000445static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
446 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000447
Bryan Duxburyc0166282009-02-02 00:48:17 +0000448 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000449 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000450 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000451 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000452 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000453 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000454 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000455 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000456 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000457 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000458 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200459 VALUE is_binary = rb_hash_aref(field_info, binary_sym);
460 if (is_binary != Qtrue) {
461 result = default_read_string(protocol);
462 } else {
463 result = default_read_binary(protocol);
464 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000465 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000466 result = default_read_double(protocol);
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500467 } else if (ttype == TTYPE_UUID) {
468 result = default_read_uuid(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000469 } else if (ttype == TTYPE_STRUCT) {
470 VALUE klass = rb_hash_aref(field_info, class_sym);
471 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000472
473 if (rb_obj_is_kind_of(result, thrift_union_class)) {
474 rb_thrift_union_read(result, protocol);
475 } else {
476 rb_thrift_struct_read(result, protocol);
477 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000478 } else if (ttype == TTYPE_MAP) {
479 int i;
480
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000481 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000482 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
483 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
484 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000485
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000486 // Check the declared key and value types against the expected ones and skip the map contents
487 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000488 VALUE key_info = rb_hash_aref(field_info, key_sym);
489 VALUE value_info = rb_hash_aref(field_info, value_sym);
490
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000491 if (!NIL_P(key_info) && !NIL_P(value_info)) {
492 int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
493 int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000494 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000495 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000496
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000497 for (i = 0; i < num_entries; ++i) {
498 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000499
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000500 key = read_anything(protocol, key_ttype, key_info);
501 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000502
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000503 rb_hash_aset(result, key, val);
504 }
505 } else {
506 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
507 }
508 } else {
509 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000510 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000511
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000512 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000513 } else if (ttype == TTYPE_LIST) {
514 int i;
515
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000516 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000517 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
518 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000519
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000520 // Check the declared element type against the expected one and skip the list contents
521 // if the types don't match.
522 VALUE element_info = rb_hash_aref(field_info, element_sym);
523 if (!NIL_P(element_info)) {
524 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
525 if (specified_element_type == element_ttype) {
526 result = rb_ary_new2(num_elements);
527
528 for (i = 0; i < num_elements; ++i) {
529 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
530 }
531 } else {
532 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
533 }
534 } else {
535 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000536 }
537
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000538 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000539 } else if (ttype == TTYPE_SET) {
540 VALUE items;
541 int i;
542
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000543 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000544 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
545 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000546
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000547 // Check the declared element type against the expected one and skip the set contents
548 // if the types don't match.
549 VALUE element_info = rb_hash_aref(field_info, element_sym);
550 if (!NIL_P(element_info)) {
551 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
552 if (specified_element_type == element_ttype) {
553 items = rb_ary_new2(num_elements);
554
555 for (i = 0; i < num_elements; ++i) {
556 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
557 }
558
559 result = rb_class_new_instance(1, &items, rb_cSet);
560 } else {
561 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
562 }
563 } else {
564 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000565 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000566
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000567 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000568 } else {
569 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
570 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000571
Bryan Duxburyc0166282009-02-02 00:48:17 +0000572 return result;
573}
574
575static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000576 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000577 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000578
579 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000580
Bryan Duxburyc0166282009-02-02 00:48:17 +0000581 // read each field
582 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000583 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000584 VALUE field_type_value = rb_ary_entry(field_header, 1);
585 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000586
Bryan Duxburyc0166282009-02-02 00:48:17 +0000587 if (field_type == TTYPE_STOP) {
588 break;
589 }
590
591 // make sure we got a type we expected
592 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
593
594 if (!NIL_P(field_info)) {
595 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
596 if (field_type == specified_type) {
597 // read the value
598 VALUE name = rb_hash_aref(field_info, name_sym);
599 set_field_value(self, name, read_anything(protocol, field_type, field_info));
600 } else {
601 rb_funcall(protocol, skip_method_id, 1, field_type_value);
602 }
603 } else {
604 rb_funcall(protocol, skip_method_id, 1, field_type_value);
605 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000606
Bryan Duxburyc0166282009-02-02 00:48:17 +0000607 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000608 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000609 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000610
Bryan Duxburyc0166282009-02-02 00:48:17 +0000611 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000612 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000613
Bryan Duxbury834895d2009-10-15 01:20:34 +0000614 // call validate
615 rb_funcall(self, validate_method_id, 0);
616
Bryan Duxburyc0166282009-02-02 00:48:17 +0000617 return Qnil;
618}
619
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000620
621// --------------------------------
622// Union section
623// --------------------------------
624
625static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
626 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000627 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000628
629 VALUE struct_fields = STRUCT_FIELDS(self);
630
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000631 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000632 VALUE field_type_value = rb_ary_entry(field_header, 1);
633 int field_type = FIX2INT(field_type_value);
634
635 // make sure we got a type we expected
636 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
637
638 if (!NIL_P(field_info)) {
639 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
640 if (field_type == specified_type) {
641 // read the value
642 VALUE name = rb_hash_aref(field_info, name_sym);
Roger Meier02405722014-01-12 23:29:11 +0100643 rb_iv_set(self, "@setfield", rb_str_intern(name));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000644 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
645 } else {
646 rb_funcall(protocol, skip_method_id, 1, field_type_value);
647 }
648 } else {
649 rb_funcall(protocol, skip_method_id, 1, field_type_value);
650 }
651
652 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000653 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000654
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000655 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000656 field_type_value = rb_ary_entry(field_header, 1);
657 field_type = FIX2INT(field_type_value);
658
659 if (field_type != TTYPE_STOP) {
Dmytro Shteflyuk32776c02026-02-10 12:25:07 -0500660 rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("too many fields in union!")));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000661 }
662
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000663 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000664 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000665
666 // call validate
667 rb_funcall(self, validate_method_id, 0);
668
669 return Qnil;
670}
671
672static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
673 // call validate
674 rb_funcall(self, validate_method_id, 0);
675
676 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000677 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000678
679 VALUE struct_fields = STRUCT_FIELDS(self);
680
681 VALUE setfield = rb_ivar_get(self, setfield_id);
682 VALUE setvalue = rb_ivar_get(self, setvalue_id);
683 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
684
685 VALUE field_info = rb_hash_aref(struct_fields, field_id);
686
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000687 if(NIL_P(field_info)) {
Dmytro Shteflyuk32776c02026-02-10 12:25:07 -0500688 rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("set_field is not valid for this union!")));
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000689 }
690
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000691 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
692 int ttype = FIX2INT(ttype_value);
693
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000694 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000695
696 write_anything(ttype, setvalue, protocol, field_info);
697
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000698 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000699
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000700 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000701
702 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000703 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000704
705 return Qnil;
706}
707
Dmytro Shteflyuk0d18fb22025-12-20 12:13:46 -0500708void Init_struct(void) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000709 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000710
Bryan Duxburyc0166282009-02-02 00:48:17 +0000711 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
712 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000713
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000714 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
Stan Hucc70b4e2021-03-11 03:49:57 +0530715 rb_global_variable(&thrift_union_class);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000716
717 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
718 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
719
720 setfield_id = rb_intern("@setfield");
Stan Hucc70b4e2021-03-11 03:49:57 +0530721 rb_global_variable(&setfield_id);
722
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000723 setvalue_id = rb_intern("@value");
Stan Hucc70b4e2021-03-11 03:49:57 +0530724 rb_global_variable(&setvalue_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000725
726 to_s_method_id = rb_intern("to_s");
Stan Hucc70b4e2021-03-11 03:49:57 +0530727 rb_global_variable(&to_s_method_id);
728
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000729 name_to_id_method_id = rb_intern("name_to_id");
Stan Hucc70b4e2021-03-11 03:49:57 +0530730 rb_global_variable(&name_to_id_method_id);
731
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000732 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Stan Hucc70b4e2021-03-11 03:49:57 +0530733 rb_global_variable(&sorted_field_ids_method_id);
Bryan Duxbury65073e52010-02-23 15:46:46 +0000734}