google-protobuf 3.7.0 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.

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 !=