sparsam 0.2.3 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4b9246d1a569e7fa72c9f97015e0f9031b31249a
4
- data.tar.gz: ba92cae518e5606f8c7273fb32519f307163b72c
2
+ SHA256:
3
+ metadata.gz: 8d2c1375a7b3b2819de7f3ee0ad85fa964fc86345ab6ae109e18a033be94178c
4
+ data.tar.gz: f47b19af1fc8810c9e06864a11c6bbfd6b78635c430c9ba2e10d578d4f3f01c4
5
5
  SHA512:
6
- metadata.gz: 268c577839d6ba4ff96b19dfdf9d09e6b903a72ef298a4cba763ed13dd4723181b85bf213e0a974ffa0abdf0a5ac131b6ef51f3fe8b42ae753ac4f3d48378afe
7
- data.tar.gz: 83b7f8c97f0feea55491958a67ae0db8805a080a0e874c27e7046211f49f74cd6b39e0f67ac1014b27a70734247ca38173dd1ece94b6dd11bf41ca0b435c9646
6
+ metadata.gz: 978c4060ced319ba2d1a24462d1c3bc917bd42f049ea591f67023631895467df7c1917734b461b9ec7c2f210f014cce5b9cd95a820a74e9d432492c80ec133fa
7
+ data.tar.gz: 948ae683123165a6e4c85537b252f882fd10e1c6f481b3641799d0635067804aaf47743aecfaca267a764bd2a4ca4ec3495a5a294871e65ab7c953efd8d6d2cb
@@ -1,6 +1,7 @@
1
+ #include <ruby.h>
2
+ #include <ruby/intern.h>
1
3
  #include "serializer.h"
2
4
  #include "stdio.h"
3
- #include <ruby.h>
4
5
 
5
6
  VALUE Sparsam = Qnil;
6
7
  VALUE static_zero_array;
@@ -10,10 +11,10 @@ ID intern_for_DEFAULT_VALUES;
10
11
  ID intern_for_assign_defaults;
11
12
  ID intern_for_assign_from_arg;
12
13
 
13
- static void deallocate(void *data) { serializer_free(data); }
14
+ static void deallocate(void* data) { serializer_free(data); }
14
15
 
15
16
  static VALUE allocate(VALUE klass) {
16
- void *data = serializer_create();
17
+ void* data = serializer_create();
17
18
  return Data_Wrap_Struct(klass, NULL, deallocate, data);
18
19
  }
19
20
 
@@ -23,8 +24,8 @@ static VALUE sparsam_init_bang(VALUE self) {
23
24
  }
24
25
 
25
26
  static VALUE initialize(VALUE self, VALUE type_arg, VALUE str_arg) {
26
- void *self_data = NULL;
27
- void *input_string = NULL;
27
+ void* self_data = NULL;
28
+ void* input_string = NULL;
28
29
 
29
30
  Check_Type(type_arg, T_FIXNUM);
30
31
  int prot = NUM2INT(type_arg);
@@ -37,7 +38,7 @@ static VALUE initialize(VALUE self, VALUE type_arg, VALUE str_arg) {
37
38
  memcpy(input_string, StringValuePtr(str_arg), len);
38
39
  }
39
40
 
40
- Data_Get_Struct(self, void *, self_data);
41
+ Data_Get_Struct(self, void*, self_data);
41
42
  serializer_init(self_data, prot, input_string, len);
42
43
 
43
44
  return self;
@@ -45,7 +46,8 @@ static VALUE initialize(VALUE self, VALUE type_arg, VALUE str_arg) {
45
46
 
46
47
  VALUE sparsam_struct_initialize(int argc, VALUE* argv, VALUE self) {
47
48
  if (argc > 1) {
48
- rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0..1)", argc);
49
+ rb_raise(rb_eArgError,
50
+ "wrong number of arguments (given %d, expected 0..1)", argc);
49
51
  }
50
52
 
51
53
  VALUE defaults = rb_const_get(rb_obj_class(self), intern_for_DEFAULT_VALUES);
@@ -69,13 +71,16 @@ void Init_sparsam_native() {
69
71
  Sparsam = rb_define_module("Sparsam");
70
72
  rb_define_singleton_method(Sparsam, "init!", sparsam_init_bang, 0);
71
73
  rb_define_singleton_method(Sparsam, "cache_fields", cache_fields, 1);
72
- VALUE SparsamSerializer = rb_define_class_under(Sparsam, "Serializer", rb_cObject);
74
+ VALUE SparsamSerializer =
75
+ rb_define_class_under(Sparsam, "Serializer", rb_cObject);
73
76
  SparsamNativeError =
74
77
  rb_define_class_under(Sparsam, "Exception", rb_eStandardError);
75
78
  rb_define_alloc_func(SparsamSerializer, allocate);
76
79
  rb_define_method(SparsamSerializer, "initialize", initialize, 2);
77
80
  rb_define_method(SparsamSerializer, "serialize", serializer_writeStruct, 2);
78
81
  rb_define_method(SparsamSerializer, "deserialize", serializer_readStruct, 1);
82
+ rb_define_method(SparsamSerializer, "deserializeUnion", serializer_readUnion,
83
+ 1);
79
84
  rb_define_const(Sparsam, "CompactProtocol", INT2FIX(compact));
80
85
  rb_define_const(Sparsam, "BinaryProtocol", INT2FIX(binary));
81
86
  rb_define_const(Sparsam, "UNION", INT2FIX(t_union));
@@ -88,8 +93,9 @@ void Init_sparsam_native() {
88
93
  intern_for_assign_defaults = rb_intern("assign_defaults");
89
94
  intern_for_assign_from_arg = rb_intern("assign_from_arg");
90
95
 
91
-
92
- VALUE SparsamStructInitialization = rb_define_module_under(Sparsam, "StructInitialization");
93
- rb_define_method(SparsamStructInitialization, "initialize", sparsam_struct_initialize, -1);
96
+ VALUE SparsamStructInitialization =
97
+ rb_define_module_under(Sparsam, "StructInitialization");
98
+ rb_define_method(SparsamStructInitialization, "initialize",
99
+ sparsam_struct_initialize, -1);
94
100
  initialize_constants();
95
101
  }
@@ -1,12 +1,16 @@
1
- #include "serializer.h"
2
- #include <functional>
3
- #include <map>
1
+ extern "C" {
2
+ #include <ruby.h>
3
+ #include <ruby/intern.h>
4
+ }
4
5
  #include <ruby/encoding.h>
5
6
  #include <stdio.h>
6
7
  #include <thrift/protocol/TBinaryProtocol.h>
7
8
  #include <thrift/protocol/TCompactProtocol.h>
8
9
  #include <boost/make_shared.hpp>
10
+ #include <functional>
11
+ #include <map>
9
12
  #include <vector>
13
+ #include "serializer.h"
10
14
 
11
15
  using namespace std;
12
16
  using ::apache::thrift::protocol::TType;
@@ -44,7 +48,7 @@ VALUE SparsamUnknownTypeException;
44
48
 
45
49
  VALUE SetClass;
46
50
 
47
- KlassFieldsCache klassCache; // consider the memory leaked.
51
+ KlassFieldsCache klassCache; // consider the memory leaked.
48
52
  std::unordered_set<VALUE> unions;
49
53
 
50
54
  void *serializer_create() { return (void *)(new ThriftSerializer()); }
@@ -79,8 +83,10 @@ void initialize_constants() {
79
83
 
80
84
  void initialize_runtime_constants() {
81
85
  klass_for_union = rb_const_get_at(Sparsam, rb_intern("Union"));
82
- SparsamMissingMandatory = rb_const_get_at(Sparsam, rb_intern("MissingMandatory"));
83
- SparsamTypeMismatchError = rb_const_get_at(Sparsam, rb_intern("TypeMismatch"));
86
+ SparsamMissingMandatory =
87
+ rb_const_get_at(Sparsam, rb_intern("MissingMandatory"));
88
+ SparsamTypeMismatchError =
89
+ rb_const_get_at(Sparsam, rb_intern("TypeMismatch"));
84
90
  SparsamUnionException = rb_const_get_at(Sparsam, rb_intern("UnionException"));
85
91
  SparsamUnknownTypeException =
86
92
  rb_const_get_at(Sparsam, rb_intern("UnknownTypeException"));
@@ -89,19 +95,16 @@ void initialize_runtime_constants() {
89
95
 
90
96
  void serializer_init(void *serializer, int protocol, void *str_arg1,
91
97
  uint32_t len) {
92
- using ::boost::shared_ptr;
93
- using ::apache::thrift::protocol::TProtocol;
94
98
  using ::apache::thrift::protocol::TBinaryProtocol;
95
99
  using ::apache::thrift::protocol::TCompactProtocol;
100
+ using ::apache::thrift::protocol::TProtocol;
101
+ using ::boost::shared_ptr;
96
102
 
97
103
  ThriftSerializer *ts = (ThriftSerializer *)(serializer);
98
104
  shared_ptr<TMemoryBuffer> strBuffer;
99
105
  if (str_arg1 != NULL) {
100
106
  strBuffer = boost::make_shared<TMemoryBuffer>(
101
- (uint8_t *)str_arg1,
102
- len,
103
- TMemoryBuffer::TAKE_OWNERSHIP
104
- );
107
+ (uint8_t *)str_arg1, len, TMemoryBuffer::TAKE_OWNERSHIP);
105
108
  } else {
106
109
  strBuffer = boost::make_shared<TMemoryBuffer>();
107
110
  }
@@ -116,21 +119,19 @@ void serializer_init(void *serializer, int protocol, void *str_arg1,
116
119
  ts->tmb = strBuffer;
117
120
  }
118
121
 
119
- #define get_ts() \
120
- void *self_data = NULL; \
121
- Data_Get_Struct(self, void, self_data); \
122
+ #define get_ts() \
123
+ void *self_data = NULL; \
124
+ Data_Get_Struct(self, void, self_data); \
122
125
  ThriftSerializer *ts = (ThriftSerializer *)(self_data);
123
126
 
124
127
  #define watch_for_texcept() try {
125
-
126
- #define catch_thrift_and_reraise() \
127
- } \
128
- catch (::apache::thrift::TException e) { \
129
- rb_raise(SparsamNativeError, "%s", e.what()); \
130
- return Qnil; \
128
+ #define catch_thrift_and_reraise() \
129
+ } \
130
+ catch (::apache::thrift::TException e) { \
131
+ rb_raise(SparsamNativeError, "%s", e.what()); \
132
+ return Qnil; \
131
133
  }
132
134
 
133
-
134
135
  static inline VALUE make_ruby_string(const string &val) {
135
136
  return rb_enc_str_new(val.c_str(), val.size(), rb_utf8_encoding());
136
137
  }
@@ -139,43 +140,58 @@ static inline VALUE make_ruby_binary(const string &val) {
139
140
  return rb_str_new(val.c_str(), val.size());
140
141
  }
141
142
 
142
- static void raise_exc_with_struct_and_field_names(
143
- VALUE exc_class,
144
- VALUE msg_prefix,
145
- VALUE outer_struct_class,
146
- VALUE field_sym) {
143
+ static void raise_exc_with_struct_and_field_names(VALUE exc_class,
144
+ VALUE msg_prefix,
145
+ VALUE outer_struct_class,
146
+ VALUE field_sym) {
147
147
  VALUE struct_name = rb_class_name(outer_struct_class);
148
148
  VALUE field_name = rb_sym_to_s(field_sym);
149
149
 
150
- VALUE msg = rb_sprintf("%s (in %s#%s)",
151
- RSTRING_PTR(msg_prefix),
152
- RSTRING_PTR(struct_name),
153
- RSTRING_PTR(field_name));
150
+ VALUE msg = rb_sprintf("%s (in %s#%s)", RSTRING_PTR(msg_prefix),
151
+ RSTRING_PTR(struct_name), RSTRING_PTR(field_name));
154
152
  VALUE args[3] = {msg, struct_name, field_name};
155
153
  VALUE e = rb_class_new_instance(3, args, exc_class);
156
154
  rb_exc_raise(e);
157
155
  }
158
156
 
159
- static void raise_type_mismatch(VALUE outer_struct, VALUE field_sym) {
160
- raise_exc_with_struct_and_field_names(
161
- SparsamTypeMismatchError,
162
- rb_str_new2("Mismatched type"),
163
- CLASS_OF(outer_struct),
164
- field_sym);
157
+ static void raise_type_mismatch(VALUE outer_struct, VALUE field_sym,
158
+ const char *expected, VALUE actual) {
159
+ VALUE actual_name = rb_class_name(CLASS_OF(actual));
160
+ VALUE msg = rb_sprintf(
161
+ "Mismatched type (expected to be compatible with: %s, found: %s)",
162
+ expected, RSTRING_PTR(actual_name));
163
+
164
+ raise_exc_with_struct_and_field_names(SparsamTypeMismatchError, msg,
165
+ CLASS_OF(outer_struct), field_sym);
165
166
  }
166
167
 
167
- static inline long raise_type_mismatch_as_value(VALUE outer_struct, VALUE field_sym) {
168
- raise_type_mismatch(outer_struct, field_sym);
168
+ static void raise_type_mismatch(VALUE outer_struct, VALUE field_sym, int ttype,
169
+ VALUE actual) {
170
+ raise_type_mismatch(outer_struct, field_sym, TTypeName((size_t)ttype).c_str(),
171
+ actual);
172
+ }
173
+
174
+ static void raise_type_mismatch(VALUE outer_struct, VALUE field_sym,
175
+ VALUE klass, VALUE actual) {
176
+ VALUE expected_name = rb_class_name(klass);
177
+ raise_type_mismatch(outer_struct, field_sym, RSTRING_PTR(expected_name),
178
+ actual);
179
+ }
180
+
181
+ static inline long raise_type_mismatch_as_value(VALUE outer_struct,
182
+ VALUE field_sym, int ttype,
183
+ VALUE actual) {
184
+ raise_type_mismatch(outer_struct, field_sym, ttype, actual);
169
185
  return 0;
170
186
  }
171
187
 
172
- static inline void Sparsam_Check_Type(VALUE x, int t, VALUE outer_struct, VALUE field_sym) {
188
+ static inline void Sparsam_Check_Type(VALUE x, int t, VALUE outer_struct,
189
+ VALUE field_sym) {
173
190
  if (!(RB_TYPE_P(x, t))) {
174
- raise_type_mismatch(outer_struct, field_sym);
191
+ raise_type_mismatch(outer_struct, field_sym, t, x);
175
192
  }
176
193
  }
177
194
 
178
-
179
195
  static inline VALUE make_ruby_bool(bool val) { return val ? Qtrue : Qfalse; }
180
196
 
181
197
  void ThriftSerializer::skip_n_type(uint32_t n, TType ttype) {
@@ -194,18 +210,17 @@ void ThriftSerializer::skip_n_pair(uint32_t n, TType type_a, TType type_b) {
194
210
  // Blatantly copied protobuf's design
195
211
  // https://git.io/vHuUn
196
212
  // CONVERT is new here, because we're targeting ruby
197
- #define HANDLE_TYPE(TYPE, CPPTYPE, READ_METHOD, CONVERT) \
198
- case protocol::T_##TYPE: { \
199
- CPPTYPE value; \
200
- this->tprot->read##READ_METHOD(value); \
201
- ret = CONVERT(value); \
202
- break; \
213
+ #define HANDLE_TYPE(TYPE, CPPTYPE, READ_METHOD, CONVERT) \
214
+ case protocol::T_##TYPE: { \
215
+ CPPTYPE value; \
216
+ this->tprot->read##READ_METHOD(value); \
217
+ ret = CONVERT(value); \
218
+ break; \
203
219
  }
204
220
 
205
221
  VALUE ThriftSerializer::readAny(TType ttype, FieldInfo *field_info) {
206
222
  VALUE ret = Qnil;
207
223
  switch (ttype) {
208
-
209
224
  // Handle all the non-container types by marco
210
225
  HANDLE_TYPE(I16, int16_t, I16, INT2FIX)
211
226
  HANDLE_TYPE(I32, int32_t, I32, INT2FIX)
@@ -214,99 +229,100 @@ VALUE ThriftSerializer::readAny(TType ttype, FieldInfo *field_info) {
214
229
  HANDLE_TYPE(DOUBLE, double, Double, DBL2NUM)
215
230
  HANDLE_TYPE(BYTE, int8_t, Byte, INT2FIX)
216
231
 
217
- case protocol::T_STRING: {
218
- string value;
219
- if (field_info->isBinaryString) { // if (field_info[:binary])
220
- this->tprot->readBinary(value);
221
- ret = make_ruby_binary(value);
222
- } else {
223
- this->tprot->readString(value);
224
- ret = make_ruby_string(value);
232
+ case protocol::T_STRING: {
233
+ string value;
234
+ if (field_info->isBinaryString) { // if (field_info[:binary])
235
+ this->tprot->readBinary(value);
236
+ ret = make_ruby_binary(value);
237
+ } else {
238
+ this->tprot->readString(value);
239
+ ret = make_ruby_string(value);
240
+ }
241
+ break;
225
242
  }
226
- break;
227
- }
228
243
 
229
- case protocol::T_LIST: {
230
- TType element_type;
231
- uint32_t size;
244
+ case protocol::T_LIST: {
245
+ TType element_type;
246
+ uint32_t size;
232
247
 
233
- this->tprot->readListBegin(element_type, size);
234
- if (field_info->elementType == NULL ||
235
- element_type != field_info->elementType->ftype) {
236
- this->skip_n_type(size, element_type);
237
- break;
238
- }
239
- ret = rb_ary_new2(size);
248
+ this->tprot->readListBegin(element_type, size);
249
+ if (field_info->elementType == NULL ||
250
+ element_type != field_info->elementType->ftype) {
251
+ this->skip_n_type(size, element_type);
252
+ break;
253
+ }
254
+ ret = rb_ary_new2(size);
255
+
256
+ for (uint32_t i = 0; i < size; i++) {
257
+ rb_ary_store(ret, i,
258
+ this->readAny(element_type, field_info->elementType));
259
+ }
260
+ this->tprot->readListEnd();
240
261
 
241
- for (uint32_t i = 0; i < size; i++) {
242
- rb_ary_store(ret, i,
243
- this->readAny(element_type, field_info->elementType));
262
+ break;
244
263
  }
245
- this->tprot->readListEnd();
246
264
 
247
- break;
248
- }
265
+ case protocol::T_SET: {
266
+ TType element_type;
267
+ uint32_t size;
249
268
 
250
- case protocol::T_SET: {
251
- TType element_type;
252
- uint32_t size;
269
+ this->tprot->readSetBegin(element_type, size);
270
+ if (field_info->elementType == NULL ||
271
+ element_type != field_info->elementType->ftype) {
272
+ this->skip_n_type(size, element_type);
273
+ break;
274
+ }
275
+ VALUE ary = rb_ary_new2(size);
253
276
 
254
- this->tprot->readSetBegin(element_type, size);
255
- if (field_info->elementType == NULL ||
256
- element_type != field_info->elementType->ftype) {
257
- this->skip_n_type(size, element_type);
277
+ for (uint32_t i = 0; i < size; i++) {
278
+ rb_ary_store(ary, i,
279
+ this->readAny(element_type, field_info->elementType));
280
+ }
281
+ ret = rb_class_new_instance(1, &ary, klass_for_set);
282
+ this->tprot->readSetEnd();
258
283
  break;
259
284
  }
260
- VALUE ary = rb_ary_new2(size);
261
285
 
262
- for (uint32_t i = 0; i < size; i++) {
263
- rb_ary_store(ary, i,
264
- this->readAny(element_type, field_info->elementType));
286
+ case protocol::T_STRUCT: {
287
+ string cname;
288
+ this->tprot->readStructBegin(cname);
289
+ if (unions.count(field_info->klass) == 1) {
290
+ ret = this->readUnion(field_info->klass);
291
+ } else {
292
+ ret = this->readStruct(field_info->klass);
293
+ }
294
+ this->tprot->readStructEnd();
295
+ break;
265
296
  }
266
- ret = rb_class_new_instance(1, &ary, klass_for_set);
267
- this->tprot->readSetEnd();
268
- break;
269
- }
270
297
 
271
- case protocol::T_STRUCT: {
272
- string cname;
273
- this->tprot->readStructBegin(cname);
274
- if (unions.count(field_info->klass) == 1) {
275
- ret = this->readUnion(field_info->klass);
276
- } else {
277
- ret = this->readStruct(field_info->klass);
278
- }
279
- this->tprot->readStructEnd();
280
- break;
281
- }
298
+ case protocol::T_MAP: {
299
+ TType key_type, value_type;
300
+ uint32_t size;
301
+ VALUE k, v;
282
302
 
283
- case protocol::T_MAP: {
284
- TType key_type, value_type;
285
- uint32_t size;
286
- VALUE k, v;
303
+ this->tprot->readMapBegin(key_type, value_type, size);
287
304
 
288
- this->tprot->readMapBegin(key_type, value_type, size);
305
+ if (field_info->keyType == NULL ||
306
+ field_info->elementType == NULL) { // no type check to be consistent
307
+ skip_n_pair(size, key_type, value_type);
308
+ break;
309
+ }
289
310
 
290
- if (field_info->keyType == NULL ||
291
- field_info->elementType == NULL) { // no type check to be consistent
292
- skip_n_pair(size, key_type, value_type);
311
+ ret = rb_hash_new();
312
+ for (uint32_t i = 0; i < size; i++) {
313
+ k = this->readAny(key_type, field_info->keyType);
314
+ v = this->readAny(value_type, field_info->elementType);
315
+ rb_hash_aset(ret, k, v);
316
+ }
317
+ this->tprot->readMapEnd();
293
318
  break;
294
319
  }
295
320
 
296
- ret = rb_hash_new();
297
- for (uint32_t i = 0; i < size; i++) {
298
- k = this->readAny(key_type, field_info->keyType);
299
- v = this->readAny(value_type, field_info->elementType);
300
- rb_hash_aset(ret, k, v);
301
- }
302
- this->tprot->readMapEnd();
303
- break;
304
- }
305
-
306
- default:
307
- this->tprot->skip(ttype);
308
- rb_raise(SparsamUnknownTypeException, "Received unknown type with id: %d", ttype);
309
- break;
321
+ default:
322
+ this->tprot->skip(ttype);
323
+ rb_raise(SparsamUnknownTypeException, "Received unknown type with id: %d",
324
+ ttype);
325
+ break;
310
326
  }
311
327
 
312
328
  return ret;
@@ -315,12 +331,11 @@ VALUE ThriftSerializer::readAny(TType ttype, FieldInfo *field_info) {
315
331
  #undef HANDLE_TYPE
316
332
 
317
333
  VALUE ThriftSerializer::readStruct(VALUE klass) {
318
-
319
334
  string cname;
320
335
  FieldBegin fieldBegin;
321
336
  TType typeId;
322
337
  FieldInfo *fieldInfo;
323
- VALUE ret = rb_class_new_instance(0, NULL, klass); // ret = &klass.new
338
+ VALUE ret = rb_class_new_instance(0, NULL, klass); // ret = &klass.new
324
339
  auto fields = FindOrCreateFieldInfoMap(klass);
325
340
 
326
341
  while (true) {
@@ -342,10 +357,11 @@ VALUE ThriftSerializer::readStruct(VALUE klass) {
342
357
 
343
358
  if (typeId != fieldBegin.ftype) {
344
359
  raise_exc_with_struct_and_field_names(
345
- SparsamTypeMismatchError,
346
- rb_sprintf("Mismatched type (definition: %d, found: %d)", fieldBegin.ftype, typeId),
347
- klass,
348
- fieldInfo->symName);
360
+ SparsamTypeMismatchError,
361
+ rb_sprintf("Mismatched type (definition: %s, found: %s)",
362
+ TTypeName(fieldBegin.ftype).c_str(),
363
+ TTypeName(typeId).c_str()),
364
+ klass, fieldInfo->symName);
349
365
  }
350
366
 
351
367
  VALUE rb_value = this->readAny(fieldBegin.ftype, iter->second);
@@ -362,7 +378,7 @@ VALUE ThriftSerializer::readUnion(VALUE klass) {
362
378
  string cname;
363
379
  FieldBegin fieldBegin;
364
380
 
365
- VALUE ret = rb_class_new_instance(0, NULL, klass); // ret = &klass.new
381
+ VALUE ret = rb_class_new_instance(0, NULL, klass); // ret = &klass.new
366
382
  auto fields = FindOrCreateFieldInfoMap(klass);
367
383
 
368
384
  VALUE key, rb_value;
@@ -400,23 +416,22 @@ VALUE ThriftSerializer::readUnion(VALUE klass) {
400
416
  // for the unary `+` before lambda:
401
417
  // https://stackoverflow.com/a/18889029/4944625
402
418
  // explicit cast to work with signature: (int (*)(...))
403
- #define HASH_FOREACH_BEGIN(hash, ...) \
404
- void *_args[] = {__VA_ARGS__}; \
419
+ #define HASH_FOREACH_BEGIN(hash, ...) \
420
+ void *_args[] = {__VA_ARGS__}; \
405
421
  rb_hash_foreach(hash, (int (*)(ANYARGS))(+[](VALUE k, VALUE v, VALUE args) { \
406
422
  void **argv = (void **) args;
407
-
408
423
  #define HASH_FOREACH_RET() return (int)ST_CONTINUE;
409
424
 
410
425
  #define HASH_FOREACH_ABORT() return (int)ST_STOP;
411
426
 
412
- #define HASH_FOREACH_END() \
413
- HASH_FOREACH_RET() \
427
+ #define HASH_FOREACH_END() \
428
+ HASH_FOREACH_RET() \
414
429
  }), (VALUE) _args);
415
430
 
416
- #define HANDLE_TYPE(TYPE, WRITE_METHOD, CONVERT) \
417
- case protocol::T_##TYPE: { \
418
- this->tprot->write##WRITE_METHOD(CONVERT); \
419
- break; \
431
+ #define HANDLE_TYPE(TYPE, WRITE_METHOD, CONVERT) \
432
+ case protocol::T_##TYPE: { \
433
+ this->tprot->write##WRITE_METHOD(CONVERT); \
434
+ break; \
420
435
  }
421
436
 
422
437
  static inline long raise_bignum_range_error_as_value() {
@@ -424,19 +439,21 @@ static inline long raise_bignum_range_error_as_value() {
424
439
  return 0;
425
440
  }
426
441
 
427
- #define CONVERT_FIXNUM(CONVERT) \
428
- ((FIXNUM_P(actual)) ? \
429
- CONVERT(actual) : \
430
- ((RB_TYPE_P(actual, T_BIGNUM)) ? \
431
- raise_bignum_range_error_as_value() : \
432
- raise_type_mismatch_as_value(outer_struct, field_sym)))
433
-
434
- #define CONVERT_I64 \
435
- ((FIXNUM_P(actual)) ? \
436
- (LONG_LONG)FIX2LONG(actual) : \
437
- ((RB_TYPE_P(actual, T_BIGNUM)) ? \
438
- rb_big2ll(actual) : \
439
- raise_type_mismatch_as_value(outer_struct, field_sym)))
442
+ #define CONVERT_FIXNUM(CONVERT, INTENDED) \
443
+ ((FIXNUM_P(actual)) \
444
+ ? CONVERT(actual) \
445
+ : ((RB_TYPE_P(actual, T_BIGNUM)) \
446
+ ? raise_bignum_range_error_as_value() \
447
+ : raise_type_mismatch_as_value(outer_struct, field_sym, \
448
+ INTENDED, actual)))
449
+
450
+ #define CONVERT_I64 \
451
+ ((FIXNUM_P(actual)) \
452
+ ? (LONG_LONG)FIX2LONG(actual) \
453
+ : ((RB_TYPE_P(actual, T_BIGNUM)) \
454
+ ? rb_big2ll(actual) \
455
+ : raise_type_mismatch_as_value(outer_struct, field_sym, \
456
+ protocol::T_I64, actual)))
440
457
 
441
458
  #ifdef RB_FLOAT_TYPE_P
442
459
  #define FLOAT_TYPE_P(x) RB_FLOAT_TYPE_P(x)
@@ -444,19 +461,21 @@ static inline long raise_bignum_range_error_as_value() {
444
461
  #define FLOAT_TYPE_P(x) RB_TYPE_P(x, T_FLOAT)
445
462
  #endif
446
463
 
447
- #define CONVERT_FLOAT(CONVERT) \
448
- ((FLOAT_TYPE_P(actual)) ? \
449
- CONVERT(actual) : \
450
- raise_type_mismatch_as_value(outer_struct, field_sym)) \
464
+ #define CONVERT_FLOAT(CONVERT) \
465
+ ((FLOAT_TYPE_P(actual)) \
466
+ ? CONVERT(actual) \
467
+ : raise_type_mismatch_as_value(outer_struct, field_sym, \
468
+ protocol::T_DOUBLE, actual))
451
469
 
452
- static inline bool convertBool(VALUE actual, VALUE outer_struct, VALUE field_sym) {
470
+ static inline bool convertBool(VALUE actual, VALUE outer_struct,
471
+ VALUE field_sym) {
453
472
  switch (actual) {
454
473
  case Qtrue:
455
474
  return true;
456
475
  case Qfalse:
457
476
  return false;
458
477
  default:
459
- raise_type_mismatch(outer_struct, field_sym);
478
+ raise_type_mismatch(outer_struct, field_sym, protocol::T_BOOL, actual);
460
479
  }
461
480
 
462
481
  /* unreachable */
@@ -473,7 +492,7 @@ static inline char byte_convert(VALUE x) {
473
492
  short s = SHORT_CONVERT(x);
474
493
 
475
494
  if (s <= 127 && s >= -128) {
476
- return (char) s;
495
+ return (char)s;
477
496
  } else {
478
497
  rb_raise(rb_eRangeError, "integer %d out of range for char", s);
479
498
  }
@@ -483,89 +502,94 @@ static inline char byte_convert(VALUE x) {
483
502
  }
484
503
 
485
504
  void ThriftSerializer::writeAny(TType ttype, FieldInfo *field_info,
486
- VALUE actual, VALUE outer_struct, VALUE field_sym) {
505
+ VALUE actual, VALUE outer_struct,
506
+ VALUE field_sym) {
487
507
  switch (ttype) {
488
- HANDLE_TYPE(I16, I16, CONVERT_FIXNUM(SHORT_CONVERT))
489
- HANDLE_TYPE(I32, I32, CONVERT_FIXNUM(FIX2INT))
508
+ HANDLE_TYPE(I16, I16, CONVERT_FIXNUM(SHORT_CONVERT, protocol::T_I16))
509
+ HANDLE_TYPE(I32, I32, CONVERT_FIXNUM(FIX2INT, protocol::T_I32))
490
510
  HANDLE_TYPE(I64, I64, CONVERT_I64)
491
511
  HANDLE_TYPE(BOOL, Bool, convertBool(actual, outer_struct, field_sym))
492
512
  HANDLE_TYPE(DOUBLE, Double, CONVERT_FLOAT(NUM2DBL))
493
- HANDLE_TYPE(BYTE, Byte, CONVERT_FIXNUM(byte_convert))
513
+ HANDLE_TYPE(BYTE, Byte, CONVERT_FIXNUM(byte_convert, protocol::T_BYTE))
494
514
 
495
- case protocol::T_STRING: {
496
- Sparsam_Check_Type(actual, T_STRING, outer_struct, field_sym);
515
+ case protocol::T_STRING: {
516
+ Sparsam_Check_Type(actual, T_STRING, outer_struct, field_sym);
497
517
 
498
- string data = string(StringValuePtr(actual), RSTRING_LEN(actual));
499
- if (field_info->isBinaryString) {
500
- this->tprot->writeBinary(data);
501
- } else {
502
- this->tprot->writeString(data);
518
+ string data = string(StringValuePtr(actual), RSTRING_LEN(actual));
519
+ if (field_info->isBinaryString) {
520
+ this->tprot->writeBinary(data);
521
+ } else {
522
+ this->tprot->writeString(data);
523
+ }
524
+ break;
503
525
  }
504
- break;
505
- }
506
526
 
507
- case protocol::T_LIST: {
508
- Sparsam_Check_Type(actual, T_ARRAY, outer_struct, field_sym);
527
+ case protocol::T_LIST: {
528
+ Sparsam_Check_Type(actual, T_ARRAY, outer_struct, field_sym);
509
529
 
510
- long length = RARRAY_LEN(actual);
511
- TType elem = field_info->elementType->ftype;
512
- this->tprot->writeListBegin(elem, static_cast<size_t>(length));
513
- for (long i = 0; i < length; i++) {
514
- this->writeAny(elem, field_info->elementType, rb_ary_entry(actual, i), outer_struct, field_sym);
530
+ long length = RARRAY_LEN(actual);
531
+ TType elem = field_info->elementType->ftype;
532
+ this->tprot->writeListBegin(elem, static_cast<size_t>(length));
533
+ for (long i = 0; i < length; i++) {
534
+ this->writeAny(elem, field_info->elementType, rb_ary_entry(actual, i),
535
+ outer_struct, field_sym);
536
+ }
537
+ this->tprot->writeListEnd();
538
+ break;
515
539
  }
516
- this->tprot->writeListEnd();
517
- break;
518
- }
519
540
 
520
- case protocol::T_SET: {
521
- if (rb_class_real(CLASS_OF(actual)) != SetClass) {
522
- raise_type_mismatch(outer_struct, field_sym);
541
+ case protocol::T_SET: {
542
+ if (rb_class_real(CLASS_OF(actual)) != SetClass) {
543
+ raise_type_mismatch(outer_struct, field_sym, protocol::T_SET, actual);
544
+ }
545
+
546
+ VALUE ary = rb_funcall(actual, intern_for_to_a, 0);
547
+ long length = RARRAY_LEN(ary);
548
+ TType elem = field_info->elementType->ftype;
549
+ this->tprot->writeListBegin(elem, static_cast<size_t>(length));
550
+ for (long i = 0; i < length; i++) {
551
+ this->writeAny(elem, field_info->elementType, rb_ary_entry(ary, i),
552
+ outer_struct, field_sym);
553
+ }
554
+ this->tprot->writeListEnd();
555
+ break;
523
556
  }
524
557
 
525
- VALUE ary = rb_funcall(actual, intern_for_to_a, 0);
526
- long length = RARRAY_LEN(ary);
527
- TType elem = field_info->elementType->ftype;
528
- this->tprot->writeListBegin(elem, static_cast<size_t>(length));
529
- for (long i = 0; i < length; i++) {
530
- this->writeAny(elem, field_info->elementType, rb_ary_entry(ary, i), outer_struct, field_sym);
558
+ case protocol::T_MAP: {
559
+ Sparsam_Check_Type(actual, T_HASH, outer_struct, field_sym);
560
+
561
+ TType keyTType = field_info->keyType->ftype,
562
+ valueTType = field_info->elementType->ftype;
563
+ this->tprot->writeMapBegin(keyTType, valueTType,
564
+ static_cast<size_t>(RHASH_SIZE(actual)));
565
+ HASH_FOREACH_BEGIN(actual, this, field_info, &outer_struct, &field_sym)
566
+ ThriftSerializer *that = (ThriftSerializer *)argv[0];
567
+ FieldInfo *field_info = (FieldInfo *)argv[1];
568
+ VALUE *outer_struct = (VALUE *)argv[2];
569
+ VALUE *field_sym = (VALUE *)argv[3];
570
+ that->writeAny(field_info->keyType->ftype, field_info->keyType, k,
571
+ *outer_struct, *field_sym);
572
+ that->writeAny(field_info->elementType->ftype, field_info->elementType, v,
573
+ *outer_struct, *field_sym);
574
+ HASH_FOREACH_END()
575
+ this->tprot->writeMapEnd();
576
+ break;
531
577
  }
532
- this->tprot->writeListEnd();
533
- break;
534
- }
535
578
 
536
- case protocol::T_MAP: {
537
- Sparsam_Check_Type(actual, T_HASH, outer_struct, field_sym);
538
-
539
- TType keyTType = field_info->keyType->ftype,
540
- valueTType = field_info->elementType->ftype;
541
- this->tprot->writeMapBegin(keyTType, valueTType,
542
- static_cast<size_t>(RHASH_SIZE(actual)));
543
- HASH_FOREACH_BEGIN(actual, this, field_info, &outer_struct, &field_sym)
544
- ThriftSerializer *that = (ThriftSerializer *)argv[0];
545
- FieldInfo *field_info = (FieldInfo *)argv[1];
546
- VALUE *outer_struct = (VALUE *)argv[2];
547
- VALUE *field_sym = (VALUE *)argv[3];
548
- that->writeAny(field_info->keyType->ftype, field_info->keyType, k, *outer_struct, *field_sym);
549
- that->writeAny(field_info->elementType->ftype, field_info->elementType, v, *outer_struct, *field_sym);
550
- HASH_FOREACH_END()
551
- this->tprot->writeMapEnd();
552
- break;
553
- }
579
+ case protocol::T_STRUCT: {
580
+ if (rb_class_real(CLASS_OF(actual)) != field_info->klass) {
581
+ raise_type_mismatch(outer_struct, field_sym, field_info->klass, actual);
582
+ }
554
583
 
555
- case protocol::T_STRUCT: {
556
- if (rb_class_real(CLASS_OF(actual)) != field_info->klass) {
557
- raise_type_mismatch(outer_struct, field_sym);
584
+ static const string cname = "";
585
+ this->tprot->writeStructBegin(cname.c_str());
586
+ this->writeStruct(field_info->klass, actual);
587
+ this->tprot->writeFieldStop();
588
+ this->tprot->writeStructEnd();
589
+ break;
558
590
  }
559
591
 
560
- static const string cname = "";
561
- this->tprot->writeStructBegin(cname.c_str());
562
- this->writeStruct(field_info->klass, actual);
563
- this->tprot->writeFieldStop();
564
- this->tprot->writeStructEnd();
565
- break;
566
- }
567
-
568
- default: { break; }
592
+ default: { break; }
569
593
  }
570
594
  }
571
595
 
@@ -578,10 +602,8 @@ static bool checkRequiredFields(VALUE klass, VALUE data) {
578
602
  VALUE val = rb_ivar_get(data, entry.second->ivarName);
579
603
  if (NIL_P(val)) {
580
604
  raise_exc_with_struct_and_field_names(
581
- SparsamMissingMandatory,
582
- rb_str_new2("Required field missing"),
583
- klass,
584
- entry.second->symName);
605
+ SparsamMissingMandatory, rb_str_new2("Required field missing"),
606
+ klass, entry.second->symName);
585
607
  return false;
586
608
  }
587
609
  }
@@ -600,14 +622,16 @@ void ThriftSerializer::writeStruct(VALUE klass, VALUE data) {
600
622
  return;
601
623
  }
602
624
 
603
- for (auto const & entry : *fields) {
625
+ for (auto const &entry : *fields) {
604
626
  fieldBegin.fid = entry.first;
605
627
  fieldInfo = entry.second;
606
628
  fieldBegin.ftype = fieldInfo->ftype;
607
629
  VALUE actual = rb_ivar_get(data, fieldInfo->ivarName);
608
630
  if (!NIL_P(actual)) {
609
- this->tprot->writeFieldBegin(cname.c_str(), fieldBegin.ftype, fieldBegin.fid);
610
- this->writeAny(fieldBegin.ftype, entry.second, actual, data, fieldInfo->symName);
631
+ this->tprot->writeFieldBegin(cname.c_str(), fieldBegin.ftype,
632
+ fieldBegin.fid);
633
+ this->writeAny(fieldBegin.ftype, entry.second, actual, data,
634
+ fieldInfo->symName);
611
635
  this->tprot->writeFieldEnd();
612
636
  }
613
637
  }
@@ -621,13 +645,10 @@ VALUE serializer_writeStruct(VALUE self, VALUE klass, VALUE data) {
621
645
  VALUE actual_name = rb_class_name(CLASS_OF(data));
622
646
 
623
647
  raise_exc_with_struct_and_field_names(
624
- SparsamTypeMismatchError,
625
- rb_sprintf(
626
- "Mismatched type passed to serialize (expected: %s got: %s)",
627
- RSTRING_PTR(expected_name),
628
- RSTRING_PTR(actual_name)),
629
- CLASS_OF(data),
630
- ID2SYM(rb_intern("(root)")));
648
+ SparsamTypeMismatchError,
649
+ rb_sprintf("Mismatched type passed to serialize (expected: %s got: %s)",
650
+ RSTRING_PTR(expected_name), RSTRING_PTR(actual_name)),
651
+ CLASS_OF(data), ID2SYM(rb_intern("(root)")));
631
652
 
632
653
  RB_GC_GUARD(expected_name);
633
654
  RB_GC_GUARD(actual_name);
@@ -654,6 +675,17 @@ VALUE serializer_readStruct(VALUE self, VALUE klass) {
654
675
  catch_thrift_and_reraise();
655
676
  }
656
677
 
678
+ VALUE serializer_readUnion(VALUE self, VALUE klass) {
679
+ watch_for_texcept() get_ts();
680
+ string cname;
681
+ VALUE ret;
682
+ ts->tprot->readStructBegin(cname);
683
+ ret = ts->readUnion(klass);
684
+ ts->tprot->readStructEnd();
685
+ return ret;
686
+ catch_thrift_and_reraise();
687
+ }
688
+
657
689
  #define R_FIX_TO_TTYPE(x) (static_cast<TType>(FIX2INT(x)))
658
690
 
659
691
  FieldInfoMap *FindOrCreateFieldInfoMap(VALUE klass) {
@@ -693,34 +725,36 @@ FieldInfo *CreateFieldInfo(VALUE field_map_entry) {
693
725
  R_FIX_TO_TTYPE(rb_hash_aref(field_map_entry, sym_for_type));
694
726
  fieldInfo->isOptional =
695
727
  RTEST(rb_hash_aref(field_map_entry, sym_for_optional));
696
- fieldInfo->ivarName = field_name_to_ivar_id(rb_hash_aref(field_map_entry, sym_for_name));
697
- fieldInfo->symName = field_name_to_sym(rb_hash_aref(field_map_entry, sym_for_name));
728
+ fieldInfo->ivarName =
729
+ field_name_to_ivar_id(rb_hash_aref(field_map_entry, sym_for_name));
730
+ fieldInfo->symName =
731
+ field_name_to_sym(rb_hash_aref(field_map_entry, sym_for_name));
698
732
  switch (fieldInfo->ftype) {
699
- case protocol::T_STRING: {
700
- if (RTEST(rb_hash_aref(field_map_entry, sym_for_binary))) {
701
- fieldInfo->isBinaryString = true;
733
+ case protocol::T_STRING: {
734
+ if (RTEST(rb_hash_aref(field_map_entry, sym_for_binary))) {
735
+ fieldInfo->isBinaryString = true;
736
+ }
737
+ break;
702
738
  }
703
- break;
704
- }
705
- case protocol::T_STRUCT: {
706
- fieldInfo->klass = rb_hash_aref(field_map_entry, sym_for_class);
707
- break;
708
- }
709
- case protocol::T_LIST:
710
- case protocol::T_SET: {
711
- fieldInfo->elementType =
712
- CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_element));
713
- break;
714
- }
715
- case protocol::T_MAP: {
716
- fieldInfo->keyType =
717
- CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_key));
718
- fieldInfo->elementType =
719
- CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_value));
720
- break;
721
- }
722
- default:
723
- break;
739
+ case protocol::T_STRUCT: {
740
+ fieldInfo->klass = rb_hash_aref(field_map_entry, sym_for_class);
741
+ break;
742
+ }
743
+ case protocol::T_LIST:
744
+ case protocol::T_SET: {
745
+ fieldInfo->elementType =
746
+ CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_element));
747
+ break;
748
+ }
749
+ case protocol::T_MAP: {
750
+ fieldInfo->keyType =
751
+ CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_key));
752
+ fieldInfo->elementType =
753
+ CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_value));
754
+ break;
755
+ }
756
+ default:
757
+ break;
724
758
  }
725
759
  return fieldInfo;
726
760
  }