google-protobuf 3.7.0 → 3.8.0

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.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccf067952a9422bea3dc504041dd23154129f98f88edf9e67e67d7cdbb6ce23c
4
- data.tar.gz: bd608b44e34348a66d1040480ad5a8e61664649c8b2158b38eb006e7662f993e
3
+ metadata.gz: acc61dfa5ec7487b0b62edbf098aca5a5d0ce33145cbab091a892f1ed9f240cf
4
+ data.tar.gz: f7666d31441737c415008dfa0077657b8afb3c23fd0966f972b305163ffd2a02
5
5
  SHA512:
6
- metadata.gz: 0711aff149212f90045fece5a507918cd1fb5d61abaa0556928c21fc69e7fe968e55d26c0123cba986005d5e28f79c655bfff02e02723d42b36d71f37a27ff13
7
- data.tar.gz: 2077de0e04653c161e5389ab0e450bcd63dcdb054a62dd9cb33a16df1e755a3cec82eca57190bd93a45774b66feb6faf457c1fe5b0dbeadac9f3bdaddc4cea82
6
+ metadata.gz: 481d523e6d2dc363c73695025811bcc181358513a9a7931d4f19d6c9aab40a085a2e02e97d5370069f339897b8170fd3ddca906952717233e582cd10a9dcfd4c
7
+ data.tar.gz: 9cf2022047f865793c3edc480147e1e2c27f1d1d676239090c32f3356a8c4f6f6405bde3b8a879aeb9200725d7e340f9fec8d1457ed37411feb3b4d0546dd96c
@@ -886,7 +886,7 @@ VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value) {
886
886
  upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
887
887
 
888
888
  switch (upb_fielddef_type(mut_def)) {
889
- case UPB_TYPE_FLOAT:
889
+ case UPB_TYPE_FLOAT:
890
890
  upb_fielddef_setdefaultfloat(mut_def, NUM2DBL(default_value));
891
891
  break;
892
892
  case UPB_TYPE_DOUBLE:
@@ -902,16 +902,16 @@ VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value) {
902
902
  upb_fielddef_setdefaultbool(mut_def, RTEST(default_value));
903
903
  break;
904
904
  case UPB_TYPE_ENUM:
905
- case UPB_TYPE_INT32:
905
+ case UPB_TYPE_INT32:
906
906
  upb_fielddef_setdefaultint32(mut_def, NUM2INT(default_value));
907
907
  break;
908
- case UPB_TYPE_INT64:
908
+ case UPB_TYPE_INT64:
909
909
  upb_fielddef_setdefaultint64(mut_def, NUM2INT(default_value));
910
910
  break;
911
- case UPB_TYPE_UINT32:
911
+ case UPB_TYPE_UINT32:
912
912
  upb_fielddef_setdefaultuint32(mut_def, NUM2UINT(default_value));
913
913
  break;
914
- case UPB_TYPE_UINT64:
914
+ case UPB_TYPE_UINT64:
915
915
  upb_fielddef_setdefaultuint64(mut_def, NUM2UINT(default_value));
916
916
  break;
917
917
  case UPB_TYPE_STRING:
@@ -2085,7 +2085,7 @@ VALUE Builder_alloc(VALUE klass) {
2085
2085
 
2086
2086
  void Builder_register(VALUE module) {
2087
2087
  VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
2088
- rb_define_alloc_func(klass, Builder_alloc);
2088
+ rb_define_alloc_func(klass, Builder_alloc);
2089
2089
  rb_define_method(klass, "initialize", Builder_initialize, 0);
2090
2090
  rb_define_method(klass, "add_file", Builder_add_file, -1);
2091
2091
  rb_define_method(klass, "add_message", Builder_add_message, 1);
@@ -2230,7 +2230,7 @@ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) {
2230
2230
  VALUE def_rb = rb_ary_entry(self->pending_list, i);
2231
2231
  if (CLASS_OF(def_rb) == cDescriptor) {
2232
2232
  self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
2233
-
2233
+
2234
2234
  if (upb_filedef_syntax(upb_def_file(self->defs[i])) == UPB_SYNTAX_PROTO3) {
2235
2235
  proto3_validate_msgdef((const upb_msgdef*)self->defs[i]);
2236
2236
  }
@@ -1061,6 +1061,11 @@ static void put_ruby_value(VALUE value,
1061
1061
  upb_sink *sink,
1062
1062
  bool emit_defaults,
1063
1063
  bool is_json) {
1064
+ if (depth > ENCODE_MAX_NESTING) {
1065
+ rb_raise(rb_eRuntimeError,
1066
+ "Maximum recursion depth exceeded during encoding.");
1067
+ }
1068
+
1064
1069
  upb_selector_t sel = 0;
1065
1070
  if (upb_fielddef_isprimitive(f)) {
1066
1071
  sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
@@ -1232,6 +1237,34 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc,
1232
1237
  upb_sink_endmsg(sink, &status);
1233
1238
  }
1234
1239
 
1240
+ static void putjsonlistvalue(
1241
+ VALUE msg_rb, const Descriptor* desc,
1242
+ upb_sink* sink, int depth, bool emit_defaults) {
1243
+ upb_status status;
1244
+ upb_sink subsink;
1245
+ MessageHeader* msg = NULL;
1246
+ const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1);
1247
+ uint32_t offset =
1248
+ desc->layout->fields[upb_fielddef_index(f)].offset +
1249
+ sizeof(MessageHeader);
1250
+ VALUE ary;
1251
+
1252
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
1253
+
1254
+ upb_sink_startmsg(sink);
1255
+
1256
+ ary = DEREF(msg, offset, VALUE);
1257
+
1258
+ if (ary == Qnil || RepeatedField_size(ary) == 0) {
1259
+ upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
1260
+ upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
1261
+ } else {
1262
+ putary(ary, f, sink, depth, emit_defaults, true);
1263
+ }
1264
+
1265
+ upb_sink_endmsg(sink, &status);
1266
+ }
1267
+
1235
1268
  static void putmsg(VALUE msg_rb, const Descriptor* desc,
1236
1269
  upb_sink *sink, int depth, bool emit_defaults,
1237
1270
  bool is_json, bool open_msg) {
@@ -1239,11 +1272,18 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
1239
1272
  upb_msg_field_iter i;
1240
1273
  upb_status status;
1241
1274
 
1242
- if (is_json && upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
1275
+ if (is_json &&
1276
+ upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
1243
1277
  putjsonany(msg_rb, desc, sink, depth, emit_defaults);
1244
1278
  return;
1245
1279
  }
1246
1280
 
1281
+ if (is_json &&
1282
+ upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_LISTVALUE) {
1283
+ putjsonlistvalue(msg_rb, desc, sink, depth, emit_defaults);
1284
+ return;
1285
+ }
1286
+
1247
1287
  if (open_msg) {
1248
1288
  upb_sink_startmsg(sink);
1249
1289
  }
@@ -82,7 +82,7 @@ static VALUE table_key(Map* self, VALUE key,
82
82
  case UPB_TYPE_INT64:
83
83
  case UPB_TYPE_UINT32:
84
84
  case UPB_TYPE_UINT64:
85
- native_slot_set(self->key_type, Qnil, buf, key);
85
+ native_slot_set("", self->key_type, Qnil, buf, key);
86
86
  *out_key = buf;
87
87
  *out_length = native_slot_size(self->key_type);
88
88
  break;
@@ -386,6 +386,8 @@ VALUE Map_index(VALUE _self, VALUE key) {
386
386
  * was just inserted.
387
387
  */
388
388
  VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
389
+ rb_check_frozen(_self);
390
+
389
391
  Map* self = ruby_to_Map(_self);
390
392
 
391
393
  char keybuf[TABLE_KEY_BUF_LENGTH];
@@ -396,7 +398,7 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
396
398
  key = table_key(self, key, keybuf, &keyval, &length);
397
399
 
398
400
  mem = value_memory(&v);
399
- native_slot_set(self->value_type, self->value_type_class, mem, value);
401
+ native_slot_set("", self->value_type, self->value_type_class, mem, value);
400
402
 
401
403
  // Replace any existing value by issuing a 'remove' operation first.
402
404
  upb_strtable_remove2(&self->table, keyval, length, NULL);
@@ -438,6 +440,8 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
438
440
  * nil if none was present. Throws an exception if the key is of the wrong type.
439
441
  */
440
442
  VALUE Map_delete(VALUE _self, VALUE key) {
443
+ rb_check_frozen(_self);
444
+
441
445
  Map* self = ruby_to_Map(_self);
442
446
 
443
447
  char keybuf[TABLE_KEY_BUF_LENGTH];
@@ -461,6 +465,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
461
465
  * Removes all entries from the map.
462
466
  */
463
467
  VALUE Map_clear(VALUE _self) {
468
+ rb_check_frozen(_self);
469
+
464
470
  Map* self = ruby_to_Map(_self);
465
471
 
466
472
  // Uninit and reinit the table -- this is faster than iterating and doing a
@@ -118,9 +118,38 @@ enum {
118
118
  METHOD_GETTER = 1,
119
119
  METHOD_SETTER = 2,
120
120
  METHOD_CLEAR = 3,
121
- METHOD_PRESENCE = 4
121
+ METHOD_PRESENCE = 4,
122
+ METHOD_ENUM_GETTER = 5,
123
+ METHOD_WRAPPER_GETTER = 6,
124
+ METHOD_WRAPPER_SETTER = 7
122
125
  };
123
126
 
127
+ // Check if the field is a well known wrapper type
128
+ static bool is_wrapper_type_field(const upb_fielddef* field) {
129
+ char* field_type_name = rb_class2name(field_type_class(field));
130
+
131
+ return strcmp(field_type_name, "Google::Protobuf::DoubleValue") == 0 ||
132
+ strcmp(field_type_name, "Google::Protobuf::FloatValue") == 0 ||
133
+ strcmp(field_type_name, "Google::Protobuf::Int32Value") == 0 ||
134
+ strcmp(field_type_name, "Google::Protobuf::Int64Value") == 0 ||
135
+ strcmp(field_type_name, "Google::Protobuf::UInt32Value") == 0 ||
136
+ strcmp(field_type_name, "Google::Protobuf::UInt64Value") == 0 ||
137
+ strcmp(field_type_name, "Google::Protobuf::BoolValue") == 0 ||
138
+ strcmp(field_type_name, "Google::Protobuf::StringValue") == 0 ||
139
+ strcmp(field_type_name, "Google::Protobuf::BytesValue") == 0;
140
+ }
141
+
142
+ // Get a new Ruby wrapper type and set the initial value
143
+ static VALUE ruby_wrapper_type(const upb_fielddef* field, const VALUE* value) {
144
+ if (is_wrapper_type_field(field) && value != Qnil) {
145
+ VALUE hash = rb_hash_new();
146
+ rb_hash_aset(hash, rb_str_new2("value"), value);
147
+ VALUE args[1] = { hash };
148
+ return rb_class_new_instance(1, args, field_type_class(field));
149
+ }
150
+ return Qnil;
151
+ }
152
+
124
153
  static int extract_method_call(VALUE method_name, MessageHeader* self,
125
154
  const upb_fielddef **f, const upb_oneofdef **o) {
126
155
  Check_Type(method_name, T_SYMBOL);
@@ -153,9 +182,62 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
153
182
  accessor_type = METHOD_GETTER;
154
183
  }
155
184
 
185
+ bool has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
186
+ &test_f, &test_o);
187
+
188
+ // Look for wrapper type accessor of the form <field_name>_as_value
189
+ if (!has_field &&
190
+ (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
191
+ name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
192
+ // Find the field name
193
+ char wrapper_field_name[name_len - 8];
194
+ strncpy(wrapper_field_name, name, name_len - 9);
195
+ wrapper_field_name[name_len - 7] = '\0';
196
+
197
+ // Check if field exists and is a wrapper type
198
+ const upb_oneofdef* test_o_wrapper;
199
+ const upb_fielddef* test_f_wrapper;
200
+ if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name, name_len - 9,
201
+ &test_f_wrapper, &test_o_wrapper) &&
202
+ upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
203
+ is_wrapper_type_field(test_f_wrapper)) {
204
+ // It does exist!
205
+ has_field = true;
206
+ if (accessor_type == METHOD_SETTER) {
207
+ accessor_type = METHOD_WRAPPER_SETTER;
208
+ } else {
209
+ accessor_type = METHOD_WRAPPER_GETTER;
210
+ }
211
+ test_o = test_o_wrapper;
212
+ test_f = test_f_wrapper;
213
+ }
214
+ }
215
+
216
+ // Look for enum accessor of the form <enum_name>_const
217
+ if (!has_field && accessor_type == METHOD_GETTER &&
218
+ name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
219
+
220
+ // Find enum field name
221
+ char enum_name[name_len - 5];
222
+ strncpy(enum_name, name, name_len - 6);
223
+ enum_name[name_len - 4] = '\0';
224
+
225
+ // Check if enum field exists
226
+ const upb_oneofdef* test_o_enum;
227
+ const upb_fielddef* test_f_enum;
228
+ if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
229
+ &test_f_enum, &test_o_enum) &&
230
+ upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
231
+ // It does exist!
232
+ has_field = true;
233
+ accessor_type = METHOD_ENUM_GETTER;
234
+ test_o = test_o_enum;
235
+ test_f = test_f_enum;
236
+ }
237
+ }
238
+
156
239
  // Verify the name corresponds to a oneof or field in this message.
157
- if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
158
- &test_f, &test_o)) {
240
+ if (!has_field) {
159
241
  return METHOD_UNKNOWN;
160
242
  }
161
243
 
@@ -212,10 +294,11 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
212
294
  int accessor_type = extract_method_call(argv[0], self, &f, &o);
213
295
  if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
214
296
  return rb_call_super(argc, argv);
215
- } else if (accessor_type == METHOD_SETTER) {
297
+ } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
216
298
  if (argc != 2) {
217
299
  rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
218
300
  }
301
+ rb_check_frozen(_self);
219
302
  } else if (argc != 1) {
220
303
  rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
221
304
  }
@@ -231,13 +314,13 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
231
314
  return oneof_field == NULL ? Qfalse : Qtrue;
232
315
  } else if (accessor_type == METHOD_CLEAR) {
233
316
  if (oneof_field != NULL) {
234
- layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
317
+ layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
235
318
  }
236
319
  return Qnil;
237
320
  } else {
238
321
  // METHOD_ACCESSOR
239
322
  return oneof_field == NULL ? Qnil :
240
- ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
323
+ ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
241
324
  }
242
325
  // Otherwise we're operating on a single proto field
243
326
  } else if (accessor_type == METHOD_SETTER) {
@@ -248,6 +331,35 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
248
331
  return Qnil;
249
332
  } else if (accessor_type == METHOD_PRESENCE) {
250
333
  return layout_has(self->descriptor->layout, Message_data(self), f);
334
+ } else if (accessor_type == METHOD_WRAPPER_GETTER) {
335
+ VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
336
+ if (value != Qnil) {
337
+ value = rb_funcall(value, rb_intern("value"), 0);
338
+ }
339
+ return value;
340
+ } else if (accessor_type == METHOD_WRAPPER_SETTER) {
341
+ VALUE wrapper = ruby_wrapper_type(f, argv[1]);
342
+ layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
343
+ return Qnil;
344
+ } else if (accessor_type == METHOD_ENUM_GETTER) {
345
+ VALUE enum_type = field_type_class(f);
346
+ VALUE method = rb_intern("const_get");
347
+ VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
348
+
349
+ // Map repeated fields to a new type with ints
350
+ if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
351
+ int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
352
+ VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
353
+ VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
354
+ for (int i = 0; i < array_size; i++) {
355
+ VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
356
+ rb_intern("at"), 1, INT2NUM(i)));
357
+ rb_funcall(array, rb_intern("push"), 1, entry);
358
+ }
359
+ return array;
360
+ }
361
+ // Convert the value for singular fields
362
+ return rb_funcall(enum_type, method, 1, raw_value);
251
363
  } else {
252
364
  return layout_get(self->descriptor->layout, Message_data(self), f);
253
365
  }
@@ -315,7 +427,8 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
315
427
 
316
428
  if (TYPE(val) != T_HASH) {
317
429
  rb_raise(rb_eArgError,
318
- "Expected Hash object as initializer value for map field '%s'.", name);
430
+ "Expected Hash object as initializer value for map field '%s' (given %s).",
431
+ name, rb_class2name(CLASS_OF(val)));
319
432
  }
320
433
  map = layout_get(self->descriptor->layout, Message_data(self), f);
321
434
  Map_merge_into_self(map, val);
@@ -324,7 +437,8 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
324
437
 
325
438
  if (TYPE(val) != T_ARRAY) {
326
439
  rb_raise(rb_eArgError,
327
- "Expected array as initializer value for repeated field '%s'.", name);
440
+ "Expected array as initializer value for repeated field '%s' (given %s).",
441
+ name, rb_class2name(CLASS_OF(val)));
328
442
  }
329
443
  ary = layout_get(self->descriptor->layout, Message_data(self), f);
330
444
  for (int i = 0; i < RARRAY_LEN(val); i++) {
@@ -620,10 +734,12 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
620
734
  // Also define #clone so that we don't inherit Object#clone.
621
735
  rb_define_method(klass, "clone", Message_dup, 0);
622
736
  rb_define_method(klass, "==", Message_eq, 1);
737
+ rb_define_method(klass, "eql?", Message_eq, 1);
623
738
  rb_define_method(klass, "hash", Message_hash, 0);
624
739
  rb_define_method(klass, "to_h", Message_to_h, 0);
625
740
  rb_define_method(klass, "to_hash", Message_to_h, 0);
626
741
  rb_define_method(klass, "inspect", Message_inspect, 0);
742
+ rb_define_method(klass, "to_s", Message_inspect, 0);
627
743
  rb_define_method(klass, "[]", Message_index, 1);
628
744
  rb_define_method(klass, "[]=", Message_index_set, 2);
629
745
  rb_define_singleton_method(klass, "decode", Message_decode, 1);
@@ -337,14 +337,16 @@ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb);
337
337
  #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
338
338
 
339
339
  size_t native_slot_size(upb_fieldtype_t type);
340
- void native_slot_set(upb_fieldtype_t type,
340
+ void native_slot_set(const char* name,
341
+ upb_fieldtype_t type,
341
342
  VALUE type_class,
342
343
  void* memory,
343
344
  VALUE value);
344
345
  // Atomically (with respect to Ruby VM calls) either update the value and set a
345
346
  // oneof case, or do neither. If |case_memory| is null, then no case value is
346
347
  // set.
347
- void native_slot_set_value_and_case(upb_fieldtype_t type,
348
+ void native_slot_set_value_and_case(const char* name,
349
+ upb_fieldtype_t type,
348
350
  VALUE type_class,
349
351
  void* memory,
350
352
  VALUE value,
@@ -360,7 +362,7 @@ void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from);
360
362
  bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2);
361
363
 
362
364
  VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value);
363
- void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value);
365
+ void native_slot_check_int_range_precision(const char* name, upb_fieldtype_t type, VALUE value);
364
366
 
365
367
  extern rb_encoding* kRubyStringUtf8Encoding;
366
368
  extern rb_encoding* kRubyStringASCIIEncoding;
@@ -178,7 +178,7 @@ VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
178
178
  }
179
179
 
180
180
  memory = RepeatedField_memoryat(self, index, element_size);
181
- native_slot_set(field_type, field_type_class, memory, val);
181
+ native_slot_set("", field_type, field_type_class, memory, val);
182
182
  return Qnil;
183
183
  }
184
184
 
@@ -217,12 +217,18 @@ VALUE RepeatedField_push(VALUE _self, VALUE val) {
217
217
 
218
218
  RepeatedField_reserve(self, self->size + 1);
219
219
  memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
220
- native_slot_set(field_type, self->field_type_class, memory, val);
220
+ native_slot_set("", field_type, self->field_type_class, memory, val);
221
221
  // native_slot_set may raise an error; bump size only after set.
222
222
  self->size++;
223
223
  return _self;
224
224
  }
225
225
 
226
+ VALUE RepeatedField_push_vararg(VALUE _self, VALUE args) {
227
+ for (int i = 0; i < RARRAY_LEN(args); i++) {
228
+ RepeatedField_push(_self, rb_ary_entry(args, i));
229
+ }
230
+ return _self;
231
+ }
226
232
 
227
233
  // Used by parsing handlers.
228
234
  void RepeatedField_push_native(VALUE _self, void* data) {
@@ -635,7 +641,7 @@ void RepeatedField_register(VALUE module) {
635
641
  rb_define_method(klass, "[]", RepeatedField_index, -1);
636
642
  rb_define_method(klass, "at", RepeatedField_index, -1);
637
643
  rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
638
- rb_define_method(klass, "push", RepeatedField_push, 1);
644
+ rb_define_method(klass, "push", RepeatedField_push_vararg, -2);
639
645
  rb_define_method(klass, "<<", RepeatedField_push, 1);
640
646
  rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0);
641
647
  rb_define_method(klass, "replace", RepeatedField_replace, 1);
@@ -65,9 +65,10 @@ static bool is_ruby_num(VALUE value) {
65
65
  TYPE(value) == T_BIGNUM);
66
66
  }
67
67
 
68
- void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
68
+ void native_slot_check_int_range_precision(const char* name, upb_fieldtype_t type, VALUE val) {
69
69
  if (!is_ruby_num(val)) {
70
- rb_raise(cTypeError, "Expected number type for integral field.");
70
+ rb_raise(cTypeError, "Expected number type for integral field '%s' (given %s).",
71
+ name, rb_class2name(CLASS_OF(val)));
71
72
  }
72
73
 
73
74
  // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
@@ -77,13 +78,15 @@ void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
77
78
  double dbl_val = NUM2DBL(val);
78
79
  if (floor(dbl_val) != dbl_val) {
79
80
  rb_raise(rb_eRangeError,
80
- "Non-integral floating point value assigned to integer field.");
81
+ "Non-integral floating point value assigned to integer field '%s' (given %s).",
82
+ name, rb_class2name(CLASS_OF(val)));
81
83
  }
82
84
  }
83
85
  if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
84
86
  if (NUM2DBL(val) < 0) {
85
87
  rb_raise(rb_eRangeError,
86
- "Assigning negative value to unsigned integer field.");
88
+ "Assigning negative value to unsigned integer field '%s' (given %s).",
89
+ name, rb_class2name(CLASS_OF(val)));
87
90
  }
88
91
  }
89
92
  }
@@ -108,12 +111,14 @@ VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value) {
108
111
  return value;
109
112
  }
110
113
 
111
- void native_slot_set(upb_fieldtype_t type, VALUE type_class,
114
+ void native_slot_set(const char* name,
115
+ upb_fieldtype_t type, VALUE type_class,
112
116
  void* memory, VALUE value) {
113
- native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
117
+ native_slot_set_value_and_case(name, type, type_class, memory, value, NULL, 0);
114
118
  }
115
119
 
116
- void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
120
+ void native_slot_set_value_and_case(const char* name,
121
+ upb_fieldtype_t type, VALUE type_class,
117
122
  void* memory, VALUE value,
118
123
  uint32_t* case_memory,
119
124
  uint32_t case_number) {
@@ -124,13 +129,15 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
124
129
  switch (type) {
125
130
  case UPB_TYPE_FLOAT:
126
131
  if (!is_ruby_num(value)) {
127
- rb_raise(cTypeError, "Expected number type for float field.");
132
+ rb_raise(cTypeError, "Expected number type for float field '%s' (given %s).",
133
+ name, rb_class2name(CLASS_OF(value)));
128
134
  }
129
135
  DEREF(memory, float) = NUM2DBL(value);
130
136
  break;
131
137
  case UPB_TYPE_DOUBLE:
132
138
  if (!is_ruby_num(value)) {
133
- rb_raise(cTypeError, "Expected number type for double field.");
139
+ rb_raise(cTypeError, "Expected number type for double field '%s' (given %s).",
140
+ name, rb_class2name(CLASS_OF(value)));
134
141
  }
135
142
  DEREF(memory, double) = NUM2DBL(value);
136
143
  break;
@@ -141,7 +148,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
141
148
  } else if (value == Qfalse) {
142
149
  val = 0;
143
150
  } else {
144
- rb_raise(cTypeError, "Invalid argument for boolean field.");
151
+ rb_raise(cTypeError, "Invalid argument for boolean field '%s' (given %s).",
152
+ name, rb_class2name(CLASS_OF(value)));
145
153
  }
146
154
  DEREF(memory, int8_t) = val;
147
155
  break;
@@ -150,7 +158,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
150
158
  if (CLASS_OF(value) == rb_cSymbol) {
151
159
  value = rb_funcall(value, rb_intern("to_s"), 0);
152
160
  } else if (CLASS_OF(value) != rb_cString) {
153
- rb_raise(cTypeError, "Invalid argument for string field.");
161
+ rb_raise(cTypeError, "Invalid argument for string field '%s' (given %s).",
162
+ name, rb_class2name(CLASS_OF(value)));
154
163
  }
155
164
 
156
165
  DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
@@ -158,7 +167,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
158
167
 
159
168
  case UPB_TYPE_BYTES: {
160
169
  if (CLASS_OF(value) != rb_cString) {
161
- rb_raise(cTypeError, "Invalid argument for string field.");
170
+ rb_raise(cTypeError, "Invalid argument for bytes field '%s' (given %s).",
171
+ name, rb_class2name(CLASS_OF(value)));
162
172
  }
163
173
 
164
174
  DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
@@ -168,9 +178,39 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
168
178
  if (CLASS_OF(value) == CLASS_OF(Qnil)) {
169
179
  value = Qnil;
170
180
  } else if (CLASS_OF(value) != type_class) {
171
- rb_raise(cTypeError,
172
- "Invalid type %s to assign to submessage field.",
173
- rb_class2name(CLASS_OF(value)));
181
+ // check for possible implicit conversions
182
+ VALUE converted_value = NULL;
183
+ char* field_type_name = rb_class2name(type_class);
184
+
185
+ if (strcmp(field_type_name, "Google::Protobuf::Timestamp") == 0 &&
186
+ rb_obj_is_kind_of(value, rb_cTime)) {
187
+ // Time -> Google::Protobuf::Timestamp
188
+ VALUE hash = rb_hash_new();
189
+ rb_hash_aset(hash, rb_str_new2("seconds"), rb_funcall(value, rb_intern("to_i"), 0));
190
+ rb_hash_aset(hash, rb_str_new2("nanos"), rb_funcall(value, rb_intern("nsec"), 0));
191
+ VALUE args[1] = { hash };
192
+ converted_value = rb_class_new_instance(1, args, type_class);
193
+ } else if (strcmp(field_type_name, "Google::Protobuf::Duration") == 0 &&
194
+ rb_obj_is_kind_of(value, rb_cNumeric)) {
195
+ // Numeric -> Google::Protobuf::Duration
196
+ VALUE hash = rb_hash_new();
197
+ rb_hash_aset(hash, rb_str_new2("seconds"), rb_funcall(value, rb_intern("to_i"), 0));
198
+ VALUE n_value = rb_funcall(value, rb_intern("remainder"), 1, INT2NUM(1));
199
+ n_value = rb_funcall(n_value, rb_intern("*"), 1, INT2NUM(1000000000));
200
+ n_value = rb_funcall(n_value, rb_intern("round"), 0);
201
+ rb_hash_aset(hash, rb_str_new2("nanos"), n_value);
202
+ VALUE args[1] = { hash };
203
+ converted_value = rb_class_new_instance(1, args, type_class);
204
+ }
205
+
206
+ // raise if no suitable conversaion could be found
207
+ if (converted_value == NULL) {
208
+ rb_raise(cTypeError,
209
+ "Invalid type %s to assign to submessage field '%s'.",
210
+ rb_class2name(CLASS_OF(value)), name);
211
+ } else {
212
+ value = converted_value;
213
+ }
174
214
  }
175
215
  DEREF(memory, VALUE) = value;
176
216
  break;
@@ -181,18 +221,18 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
181
221
  value = rb_funcall(value, rb_intern("to_sym"), 0);
182
222
  } else if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
183
223
  rb_raise(cTypeError,
184
- "Expected number or symbol type for enum field.");
224
+ "Expected number or symbol type for enum field '%s'.", name);
185
225
  }
186
226
  if (TYPE(value) == T_SYMBOL) {
187
227
  // Ensure that the given symbol exists in the enum module.
188
228
  VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
189
229
  if (lookup == Qnil) {
190
- rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
230
+ rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name);
191
231
  } else {
192
232
  int_val = NUM2INT(lookup);
193
233
  }
194
234
  } else {
195
- native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
235
+ native_slot_check_int_range_precision(name, UPB_TYPE_INT32, value);
196
236
  int_val = NUM2INT(value);
197
237
  }
198
238
  DEREF(memory, int32_t) = int_val;
@@ -202,7 +242,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
202
242
  case UPB_TYPE_INT64:
203
243
  case UPB_TYPE_UINT32:
204
244
  case UPB_TYPE_UINT64:
205
- native_slot_check_int_range_precision(type, value);
245
+ native_slot_check_int_range_precision(name, type, value);
206
246
  switch (type) {
207
247
  case UPB_TYPE_INT32:
208
248
  DEREF(memory, int32_t) = NUM2INT(value);
@@ -658,8 +698,9 @@ void layout_clear(MessageLayout* layout,
658
698
 
659
699
  DEREF(memory, VALUE) = ary;
660
700
  } else {
661
- native_slot_set(upb_fielddef_type(field), field_type_class(field),
662
- memory, layout_get_default(field));
701
+ native_slot_set(upb_fielddef_name(field),
702
+ upb_fielddef_type(field), field_type_class(field),
703
+ memory, layout_get_default(field));
663
704
  }
664
705
  }
665
706
 
@@ -816,6 +857,7 @@ void layout_set(MessageLayout* layout,
816
857
  // use native_slot_set_value_and_case(), which ensures that both the value
817
858
  // and case number are altered atomically (w.r.t. the Ruby VM).
818
859
  native_slot_set_value_and_case(
860
+ upb_fielddef_name(field),
819
861
  upb_fielddef_type(field), field_type_class(field),
820
862
  memory, val,
821
863
  oneof_case, upb_fielddef_number(field));
@@ -827,8 +869,9 @@ void layout_set(MessageLayout* layout,
827
869
  check_repeated_field_type(val, field);
828
870
  DEREF(memory, VALUE) = val;
829
871
  } else {
830
- native_slot_set(upb_fielddef_type(field), field_type_class(field), memory,
831
- val);
872
+ native_slot_set(upb_fielddef_name(field),
873
+ upb_fielddef_type(field), field_type_class(field),
874
+ memory, val);
832
875
  }
833
876
 
834
877
  if (layout->fields[upb_fielddef_index(field)].hasbit !=