blob: cdc11db701ed20dcda2bf5cc0255daa1f23505bc [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
Dmytro Shteflyuk5b5fd3c2026-03-11 19:50:50 -040038static VALUE new_container_array(int size) {
39 if (size < 0) {
40 rb_exc_raise(
41 get_protocol_exception(
42 INT2FIX(PROTOERR_NEGATIVE_SIZE),
43 rb_str_new2("Negative container size")
44 )
45 );
46 }
47
48 return rb_ary_new2(size > 1024 ? 1024 : size);
49}
50
Bryan Duxburyc0166282009-02-02 00:48:17 +000051//-------------------------------------------
52// Writing section
53//-------------------------------------------
54
55// default fn pointers for protocol stuff here
56
57VALUE default_write_bool(VALUE protocol, VALUE value) {
58 rb_funcall(protocol, write_boolean_method_id, 1, value);
59 return Qnil;
60}
61
62VALUE default_write_byte(VALUE protocol, VALUE value) {
63 rb_funcall(protocol, write_byte_method_id, 1, value);
64 return Qnil;
65}
66
67VALUE default_write_i16(VALUE protocol, VALUE value) {
68 rb_funcall(protocol, write_i16_method_id, 1, value);
69 return Qnil;
70}
71
72VALUE default_write_i32(VALUE protocol, VALUE value) {
73 rb_funcall(protocol, write_i32_method_id, 1, value);
74 return Qnil;
75}
76
77VALUE default_write_i64(VALUE protocol, VALUE value) {
78 rb_funcall(protocol, write_i64_method_id, 1, value);
79 return Qnil;
80}
81
82VALUE default_write_double(VALUE protocol, VALUE value) {
83 rb_funcall(protocol, write_double_method_id, 1, value);
84 return Qnil;
85}
86
87VALUE default_write_string(VALUE protocol, VALUE value) {
88 rb_funcall(protocol, write_string_method_id, 1, value);
89 return Qnil;
90}
91
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -050092VALUE default_write_uuid(VALUE protocol, VALUE value) {
93 rb_funcall(protocol, write_uuid_method_id, 1, value);
94 return Qnil;
95}
96
henrique8a2bab32014-07-16 20:10:57 +020097VALUE default_write_binary(VALUE protocol, VALUE value) {
98 rb_funcall(protocol, write_binary_method_id, 1, value);
99 return Qnil;
100}
101
Bryan Duxburyc0166282009-02-02 00:48:17 +0000102VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
103 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
104 return Qnil;
105}
106
107VALUE default_write_list_end(VALUE protocol) {
108 rb_funcall(protocol, write_list_end_method_id, 0);
109 return Qnil;
110}
111
112VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
113 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
114 return Qnil;
115}
116
117VALUE default_write_set_end(VALUE protocol) {
118 rb_funcall(protocol, write_set_end_method_id, 0);
119 return Qnil;
120}
121
122VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
123 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
124 return Qnil;
125}
126
127VALUE default_write_map_end(VALUE protocol) {
128 rb_funcall(protocol, write_map_end_method_id, 0);
129 return Qnil;
130}
131
132VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
133 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
134 return Qnil;
135}
136
137VALUE default_write_struct_end(VALUE protocol) {
138 rb_funcall(protocol, write_struct_end_method_id, 0);
139 return Qnil;
140}
141
142VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
143 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
144 return Qnil;
145}
146
147VALUE default_write_field_end(VALUE protocol) {
148 rb_funcall(protocol, write_field_end_method_id, 0);
149 return Qnil;
150}
151
152VALUE default_write_field_stop(VALUE protocol) {
153 rb_funcall(protocol, write_field_stop_method_id, 0);
154 return Qnil;
155}
156
157VALUE default_read_field_begin(VALUE protocol) {
158 return rb_funcall(protocol, read_field_begin_method_id, 0);
159}
160
161VALUE default_read_field_end(VALUE protocol) {
162 return rb_funcall(protocol, read_field_end_method_id, 0);
163}
164
165VALUE default_read_map_begin(VALUE protocol) {
166 return rb_funcall(protocol, read_map_begin_method_id, 0);
167}
168
169VALUE default_read_map_end(VALUE protocol) {
170 return rb_funcall(protocol, read_map_end_method_id, 0);
171}
172
173VALUE default_read_list_begin(VALUE protocol) {
174 return rb_funcall(protocol, read_list_begin_method_id, 0);
175}
176
177VALUE default_read_list_end(VALUE protocol) {
178 return rb_funcall(protocol, read_list_end_method_id, 0);
179}
180
181VALUE default_read_set_begin(VALUE protocol) {
182 return rb_funcall(protocol, read_set_begin_method_id, 0);
183}
184
185VALUE default_read_set_end(VALUE protocol) {
186 return rb_funcall(protocol, read_set_end_method_id, 0);
187}
188
189VALUE default_read_byte(VALUE protocol) {
190 return rb_funcall(protocol, read_byte_method_id, 0);
191}
192
193VALUE default_read_bool(VALUE protocol) {
194 return rb_funcall(protocol, read_bool_method_id, 0);
195}
196
197VALUE default_read_i16(VALUE protocol) {
198 return rb_funcall(protocol, read_i16_method_id, 0);
199}
200
201VALUE default_read_i32(VALUE protocol) {
202 return rb_funcall(protocol, read_i32_method_id, 0);
203}
204
205VALUE default_read_i64(VALUE protocol) {
206 return rb_funcall(protocol, read_i64_method_id, 0);
207}
208
209VALUE default_read_double(VALUE protocol) {
210 return rb_funcall(protocol, read_double_method_id, 0);
211}
212
213VALUE default_read_string(VALUE protocol) {
214 return rb_funcall(protocol, read_string_method_id, 0);
215}
216
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500217VALUE default_read_uuid(VALUE protocol) {
218 return rb_funcall(protocol, read_uuid_method_id, 0);
219}
220
henrique8a2bab32014-07-16 20:10:57 +0200221VALUE default_read_binary(VALUE protocol) {
222 return rb_funcall(protocol, read_binary_method_id, 0);
223}
224
Bryan Duxburyc0166282009-02-02 00:48:17 +0000225VALUE default_read_struct_begin(VALUE protocol) {
226 return rb_funcall(protocol, read_struct_begin_method_id, 0);
227}
228
229VALUE default_read_struct_end(VALUE protocol) {
230 return rb_funcall(protocol, read_struct_end_method_id, 0);
231}
232
Bryan Duxburyc0166282009-02-02 00:48:17 +0000233// end default protocol methods
234
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000235static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000236static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
237static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
238
239VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000240 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000241
Bryan Duxburyc0166282009-02-02 00:48:17 +0000242 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000243 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000244
245 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000246
Bryan Duxburyc0166282009-02-02 00:48:17 +0000247 return value;
248}
249
250static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
Jean Boussier1e843412021-10-13 12:36:28 +0200251 long sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000252
Bryan Duxburyc0166282009-02-02 00:48:17 +0000253 if (ttype == TTYPE_MAP) {
254 VALUE keys;
255 VALUE key;
256 VALUE val;
257
258 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000259
Bryan Duxburyc0166282009-02-02 00:48:17 +0000260 VALUE key_info = rb_hash_aref(field_info, key_sym);
261 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
262 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000263
Bryan Duxburyc0166282009-02-02 00:48:17 +0000264 VALUE value_info = rb_hash_aref(field_info, value_sym);
265 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
266 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000267
Bryan Duxburyc0166282009-02-02 00:48:17 +0000268 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000269
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000270 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000271
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000272 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000273
Bryan Duxburyc0166282009-02-02 00:48:17 +0000274 for (i = 0; i < sz; i++) {
275 key = rb_ary_entry(keys, i);
276 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000277
Bryan Duxburyc0166282009-02-02 00:48:17 +0000278 if (IS_CONTAINER(keytype)) {
279 write_container(keytype, key_info, key, protocol);
280 } else {
281 write_anything(keytype, key, protocol, key_info);
282 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000283
Bryan Duxburyc0166282009-02-02 00:48:17 +0000284 if (IS_CONTAINER(valuetype)) {
285 write_container(valuetype, value_info, val, protocol);
286 } else {
287 write_anything(valuetype, val, protocol, value_info);
288 }
289 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000290
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000291 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000292 } else if (ttype == TTYPE_LIST) {
293 Check_Type(value, T_ARRAY);
294
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000295 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000296
297 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
298 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
299 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000300
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000301 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000302 for (i = 0; i < sz; ++i) {
303 VALUE val = rb_ary_entry(value, i);
304 if (IS_CONTAINER(element_type)) {
305 write_container(element_type, element_type_info, val, protocol);
306 } else {
307 write_anything(element_type, val, protocol, element_type_info);
308 }
309 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000310 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000311 } else if (ttype == TTYPE_SET) {
312 VALUE items;
313
314 if (TYPE(value) == T_ARRAY) {
315 items = value;
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000316 } else {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000317 if (rb_cSet == CLASS_OF(value)) {
318 items = rb_funcall(value, entries_method_id, 0);
319 } else {
320 Check_Type(value, T_HASH);
321 items = rb_funcall(value, keys_method_id, 0);
322 }
323 }
324
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000325 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000326
327 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
328 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
329 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000330
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000331 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000332
Bryan Duxburyc0166282009-02-02 00:48:17 +0000333 for (i = 0; i < sz; i++) {
334 VALUE val = rb_ary_entry(items, i);
335 if (IS_CONTAINER(element_type)) {
336 write_container(element_type, element_type_info, val, protocol);
337 } else {
338 write_anything(element_type, val, protocol, element_type_info);
339 }
340 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000341
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000342 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000343 } else {
344 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
345 }
346}
347
348static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
349 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000350 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000351 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000352 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000353 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000354 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000355 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000356 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000357 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000358 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000359 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000360 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000361 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200362 VALUE is_binary = rb_hash_aref(field_info, binary_sym);
363 if (is_binary != Qtrue) {
364 default_write_string(protocol, value);
365 } else {
366 default_write_binary(protocol, value);
367 }
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500368 } else if (ttype == TTYPE_UUID) {
369 default_write_uuid(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000370 } else if (IS_CONTAINER(ttype)) {
371 write_container(ttype, field_info, value, protocol);
372 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000373 if (rb_obj_is_kind_of(value, thrift_union_class)) {
374 rb_thrift_union_write(value, protocol);
375 } else {
376 rb_thrift_struct_write(value, protocol);
377 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000378 } else {
379 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
380 }
381}
382
383static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
384 // call validate
385 rb_funcall(self, validate_method_id, 0);
386
Bryan Duxburyc0166282009-02-02 00:48:17 +0000387 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000388 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000389
Bryan Duxburyc0166282009-02-02 00:48:17 +0000390 // iterate through all the fields here
391 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000392 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000393
Bryan Duxburyc0166282009-02-02 00:48:17 +0000394 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000395 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
396 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000397
Bryan Duxburyc0166282009-02-02 00:48:17 +0000398 VALUE field_info = rb_hash_aref(struct_fields, field_id);
399
400 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
401 int ttype = FIX2INT(ttype_value);
402 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000403
Bryan Duxburyc0166282009-02-02 00:48:17 +0000404 VALUE field_value = get_field_value(self, field_name);
405
406 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000407 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000408
Bryan Duxburyc0166282009-02-02 00:48:17 +0000409 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000410
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000411 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000412 }
413 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000414
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000415 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000416
Bryan Duxburyc0166282009-02-02 00:48:17 +0000417 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000418 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000419
Bryan Duxburyc0166282009-02-02 00:48:17 +0000420 return Qnil;
421}
422
423//-------------------------------------------
424// Reading section
425//-------------------------------------------
426
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000427static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000428static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000429static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
430static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000431
432static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000433 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000434
435 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000436 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000437
438 rb_ivar_set(obj, rb_intern(name_buf), value);
439}
440
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000441// Helper method to skip the contents of a map (assumes the map header has been read).
442static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
443 int i;
444 for (i = 0; i < size; i++) {
445 rb_funcall(protocol, skip_method_id, 1, key_type_value);
446 rb_funcall(protocol, skip_method_id, 1, value_type_value);
447 }
448}
449
450// Helper method to skip the contents of a list or set (assumes the list/set header has been read).
451static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
452 int i;
453 for (i = 0; i < size; i++) {
454 rb_funcall(protocol, skip_method_id, 1, element_type_value);
455 }
456}
457
Bryan Duxburyc0166282009-02-02 00:48:17 +0000458static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
459 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000460
Bryan Duxburyc0166282009-02-02 00:48:17 +0000461 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000462 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000463 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000464 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000465 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000466 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000467 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000468 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000469 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000470 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000471 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200472 VALUE is_binary = rb_hash_aref(field_info, binary_sym);
473 if (is_binary != Qtrue) {
474 result = default_read_string(protocol);
475 } else {
476 result = default_read_binary(protocol);
477 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000478 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000479 result = default_read_double(protocol);
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -0500480 } else if (ttype == TTYPE_UUID) {
481 result = default_read_uuid(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000482 } else if (ttype == TTYPE_STRUCT) {
483 VALUE klass = rb_hash_aref(field_info, class_sym);
484 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000485
486 if (rb_obj_is_kind_of(result, thrift_union_class)) {
487 rb_thrift_union_read(result, protocol);
488 } else {
489 rb_thrift_struct_read(result, protocol);
490 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000491 } else if (ttype == TTYPE_MAP) {
492 int i;
493
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000494 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000495 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
496 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
497 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000498
Dmytro Shteflyuk5b5fd3c2026-03-11 19:50:50 -0400499 if (num_entries < 0) {
500 rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_NEGATIVE_SIZE), rb_str_new2("Negative container size")));
501 }
502
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000503 // Check the declared key and value types against the expected ones and skip the map contents
504 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000505 VALUE key_info = rb_hash_aref(field_info, key_sym);
506 VALUE value_info = rb_hash_aref(field_info, value_sym);
507
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000508 if (!NIL_P(key_info) && !NIL_P(value_info)) {
509 int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
510 int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000511 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000512 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000513
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000514 for (i = 0; i < num_entries; ++i) {
515 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000516
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000517 key = read_anything(protocol, key_ttype, key_info);
518 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000519
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000520 rb_hash_aset(result, key, val);
521 }
522 } else {
523 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
524 }
525 } else {
526 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000527 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000528
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000529 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000530 } else if (ttype == TTYPE_LIST) {
531 int i;
532
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000533 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000534 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
535 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000536
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000537 // Check the declared element type against the expected one and skip the list contents
538 // if the types don't match.
539 VALUE element_info = rb_hash_aref(field_info, element_sym);
540 if (!NIL_P(element_info)) {
541 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
542 if (specified_element_type == element_ttype) {
Dmytro Shteflyuk5b5fd3c2026-03-11 19:50:50 -0400543 result = new_container_array(num_elements);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000544
545 for (i = 0; i < num_elements; ++i) {
546 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
547 }
548 } else {
549 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
550 }
551 } else {
552 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000553 }
554
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000555 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000556 } else if (ttype == TTYPE_SET) {
557 VALUE items;
558 int i;
559
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000560 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000561 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
562 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000563
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000564 // Check the declared element type against the expected one and skip the set contents
565 // if the types don't match.
566 VALUE element_info = rb_hash_aref(field_info, element_sym);
567 if (!NIL_P(element_info)) {
568 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
569 if (specified_element_type == element_ttype) {
Dmytro Shteflyuk5b5fd3c2026-03-11 19:50:50 -0400570 items = new_container_array(num_elements);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000571
572 for (i = 0; i < num_elements; ++i) {
573 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
574 }
575
576 result = rb_class_new_instance(1, &items, rb_cSet);
577 } else {
578 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
579 }
580 } else {
581 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000582 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000583
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000584 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000585 } else {
586 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
587 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000588
Bryan Duxburyc0166282009-02-02 00:48:17 +0000589 return result;
590}
591
592static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000593 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000594 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000595
596 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000597
Bryan Duxburyc0166282009-02-02 00:48:17 +0000598 // read each field
599 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000600 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000601 VALUE field_type_value = rb_ary_entry(field_header, 1);
602 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000603
Bryan Duxburyc0166282009-02-02 00:48:17 +0000604 if (field_type == TTYPE_STOP) {
605 break;
606 }
607
608 // make sure we got a type we expected
609 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
610
611 if (!NIL_P(field_info)) {
612 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
613 if (field_type == specified_type) {
614 // read the value
615 VALUE name = rb_hash_aref(field_info, name_sym);
616 set_field_value(self, name, read_anything(protocol, field_type, field_info));
617 } else {
618 rb_funcall(protocol, skip_method_id, 1, field_type_value);
619 }
620 } else {
621 rb_funcall(protocol, skip_method_id, 1, field_type_value);
622 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000623
Bryan Duxburyc0166282009-02-02 00:48:17 +0000624 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000625 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000626 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000627
Bryan Duxburyc0166282009-02-02 00:48:17 +0000628 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000629 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000630
Bryan Duxbury834895d2009-10-15 01:20:34 +0000631 // call validate
632 rb_funcall(self, validate_method_id, 0);
633
Bryan Duxburyc0166282009-02-02 00:48:17 +0000634 return Qnil;
635}
636
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000637
638// --------------------------------
639// Union section
640// --------------------------------
641
642static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
643 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000644 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000645
646 VALUE struct_fields = STRUCT_FIELDS(self);
647
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000648 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000649 VALUE field_type_value = rb_ary_entry(field_header, 1);
650 int field_type = FIX2INT(field_type_value);
651
652 // make sure we got a type we expected
653 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
654
655 if (!NIL_P(field_info)) {
656 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
657 if (field_type == specified_type) {
658 // read the value
659 VALUE name = rb_hash_aref(field_info, name_sym);
Roger Meier02405722014-01-12 23:29:11 +0100660 rb_iv_set(self, "@setfield", rb_str_intern(name));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000661 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
662 } else {
663 rb_funcall(protocol, skip_method_id, 1, field_type_value);
664 }
665 } else {
666 rb_funcall(protocol, skip_method_id, 1, field_type_value);
667 }
668
669 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000670 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000671
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000672 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000673 field_type_value = rb_ary_entry(field_header, 1);
674 field_type = FIX2INT(field_type_value);
675
676 if (field_type != TTYPE_STOP) {
Dmytro Shteflyuk32776c02026-02-10 12:25:07 -0500677 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 +0000678 }
679
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000680 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000681 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000682
683 // call validate
684 rb_funcall(self, validate_method_id, 0);
685
686 return Qnil;
687}
688
689static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
690 // call validate
691 rb_funcall(self, validate_method_id, 0);
692
693 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000694 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000695
696 VALUE struct_fields = STRUCT_FIELDS(self);
697
698 VALUE setfield = rb_ivar_get(self, setfield_id);
699 VALUE setvalue = rb_ivar_get(self, setvalue_id);
700 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
701
702 VALUE field_info = rb_hash_aref(struct_fields, field_id);
703
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000704 if(NIL_P(field_info)) {
Dmytro Shteflyuk32776c02026-02-10 12:25:07 -0500705 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 +0000706 }
707
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000708 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
709 int ttype = FIX2INT(ttype_value);
710
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000711 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000712
713 write_anything(ttype, setvalue, protocol, field_info);
714
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000715 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000716
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000717 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000718
719 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000720 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000721
722 return Qnil;
723}
724
Dmytro Shteflyuk0d18fb22025-12-20 12:13:46 -0500725void Init_struct(void) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000726 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000727
Bryan Duxburyc0166282009-02-02 00:48:17 +0000728 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
729 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000730
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000731 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
Stan Hucc70b4e2021-03-11 03:49:57 +0530732 rb_global_variable(&thrift_union_class);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000733
734 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
735 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
736
737 setfield_id = rb_intern("@setfield");
Stan Hucc70b4e2021-03-11 03:49:57 +0530738 rb_global_variable(&setfield_id);
739
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000740 setvalue_id = rb_intern("@value");
Stan Hucc70b4e2021-03-11 03:49:57 +0530741 rb_global_variable(&setvalue_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000742
743 to_s_method_id = rb_intern("to_s");
Stan Hucc70b4e2021-03-11 03:49:57 +0530744 rb_global_variable(&to_s_method_id);
745
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000746 name_to_id_method_id = rb_intern("name_to_id");
Stan Hucc70b4e2021-03-11 03:49:57 +0530747 rb_global_variable(&name_to_id_method_id);
748
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000749 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Stan Hucc70b4e2021-03-11 03:49:57 +0530750 rb_global_variable(&sorted_field_ids_method_id);
Bryan Duxbury65073e52010-02-23 15:46:46 +0000751}