sparsam 0.2.3 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
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
  }