google-protobuf 3.2.0 → 3.9.1

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.

@@ -2,9 +2,22 @@
2
2
 
3
3
  require 'mkmf'
4
4
 
5
- $CFLAGS += " -std=c99 -O3 -DNDEBUG"
5
+ if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
6
+ # XOPEN_SOURCE needed for strptime:
7
+ # https://stackoverflow.com/questions/35234152/strptime-giving-implicit-declaration-and-undefined-reference
8
+ $CFLAGS += " -std=c99 -O3 -DNDEBUG -D_XOPEN_SOURCE=700"
9
+ else
10
+ $CFLAGS += " -std=c99 -O3 -DNDEBUG"
11
+ end
12
+
13
+
14
+ if RUBY_PLATFORM =~ /linux/
15
+ # Instruct the linker to point memcpy calls at our __wrap_memcpy wrapper.
16
+ $LDFLAGS += " -Wl,-wrap,memcpy"
17
+ end
6
18
 
7
19
  $objs = ["protobuf.o", "defs.o", "storage.o", "message.o",
8
- "repeated_field.o", "map.o", "encode_decode.o", "upb.o"]
20
+ "repeated_field.o", "map.o", "encode_decode.o", "upb.o",
21
+ "wrap_memcpy.o"]
9
22
 
10
23
  create_makefile("google/protobuf_c")
@@ -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;
@@ -146,6 +146,7 @@ void Map_mark(void* _self) {
146
146
  Map* self = _self;
147
147
 
148
148
  rb_gc_mark(self->value_type_class);
149
+ rb_gc_mark(self->parse_frame);
149
150
 
150
151
  if (self->value_type == UPB_TYPE_STRING ||
151
152
  self->value_type == UPB_TYPE_BYTES ||
@@ -174,6 +175,12 @@ VALUE Map_alloc(VALUE klass) {
174
175
  return TypedData_Wrap_Struct(klass, &Map_type, self);
175
176
  }
176
177
 
178
+ VALUE Map_set_frame(VALUE map, VALUE val) {
179
+ Map* self = ruby_to_Map(map);
180
+ self->parse_frame = val;
181
+ return val;
182
+ }
183
+
177
184
  static bool needs_typeclass(upb_fieldtype_t type) {
178
185
  switch (type) {
179
186
  case UPB_TYPE_MESSAGE:
@@ -227,6 +234,7 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
227
234
 
228
235
  self->key_type = ruby_to_fieldtype(argv[0]);
229
236
  self->value_type = ruby_to_fieldtype(argv[1]);
237
+ self->parse_frame = Qnil;
230
238
 
231
239
  // Check that the key type is an allowed type.
232
240
  switch (self->key_type) {
@@ -378,6 +386,8 @@ VALUE Map_index(VALUE _self, VALUE key) {
378
386
  * was just inserted.
379
387
  */
380
388
  VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
389
+ rb_check_frozen(_self);
390
+
381
391
  Map* self = ruby_to_Map(_self);
382
392
 
383
393
  char keybuf[TABLE_KEY_BUF_LENGTH];
@@ -388,7 +398,7 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
388
398
  key = table_key(self, key, keybuf, &keyval, &length);
389
399
 
390
400
  mem = value_memory(&v);
391
- 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);
392
402
 
393
403
  // Replace any existing value by issuing a 'remove' operation first.
394
404
  upb_strtable_remove2(&self->table, keyval, length, NULL);
@@ -430,6 +440,8 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
430
440
  * nil if none was present. Throws an exception if the key is of the wrong type.
431
441
  */
432
442
  VALUE Map_delete(VALUE _self, VALUE key) {
443
+ rb_check_frozen(_self);
444
+
433
445
  Map* self = ruby_to_Map(_self);
434
446
 
435
447
  char keybuf[TABLE_KEY_BUF_LENGTH];
@@ -453,6 +465,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
453
465
  * Removes all entries from the map.
454
466
  */
455
467
  VALUE Map_clear(VALUE _self) {
468
+ rb_check_frozen(_self);
469
+
456
470
  Map* self = ruby_to_Map(_self);
457
471
 
458
472
  // Uninit and reinit the table -- this is faster than iterating and doing a
@@ -652,6 +666,35 @@ VALUE Map_hash(VALUE _self) {
652
666
  return INT2FIX(h);
653
667
  }
654
668
 
669
+ /*
670
+ * call-seq:
671
+ * Map.to_h => {}
672
+ *
673
+ * Returns a Ruby Hash object containing all the values within the map
674
+ */
675
+ VALUE Map_to_h(VALUE _self) {
676
+ Map* self = ruby_to_Map(_self);
677
+ VALUE hash = rb_hash_new();
678
+ upb_strtable_iter it;
679
+ for (upb_strtable_begin(&it, &self->table);
680
+ !upb_strtable_done(&it);
681
+ upb_strtable_next(&it)) {
682
+ VALUE key = table_key_to_ruby(
683
+ self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
684
+ upb_value v = upb_strtable_iter_value(&it);
685
+ void* mem = value_memory(&v);
686
+ VALUE value = native_slot_get(self->value_type,
687
+ self->value_type_class,
688
+ mem);
689
+
690
+ if (self->value_type == UPB_TYPE_MESSAGE) {
691
+ value = Message_to_h(value);
692
+ }
693
+ rb_hash_aset(hash, key, value);
694
+ }
695
+ return hash;
696
+ }
697
+
655
698
  /*
656
699
  * call-seq:
657
700
  * Map.inspect => string
@@ -788,8 +831,8 @@ VALUE Map_iter_value(Map_iter* iter) {
788
831
  void Map_register(VALUE module) {
789
832
  VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
790
833
  rb_define_alloc_func(klass, Map_alloc);
791
- cMap = klass;
792
834
  rb_gc_register_address(&cMap);
835
+ cMap = klass;
793
836
 
794
837
  rb_define_method(klass, "initialize", Map_init, -1);
795
838
  rb_define_method(klass, "each", Map_each, 0);
@@ -804,6 +847,7 @@ void Map_register(VALUE module) {
804
847
  rb_define_method(klass, "dup", Map_dup, 0);
805
848
  rb_define_method(klass, "==", Map_eq, 1);
806
849
  rb_define_method(klass, "hash", Map_hash, 0);
850
+ rb_define_method(klass, "to_h", Map_to_h, 0);
807
851
  rb_define_method(klass, "inspect", Map_inspect, 0);
808
852
  rb_define_method(klass, "merge", Map_merge, 1);
809
853
  rb_include_module(klass, rb_mEnumerable);
@@ -44,6 +44,11 @@ void Message_mark(void* _self) {
44
44
  }
45
45
 
46
46
  void Message_free(void* self) {
47
+ stringsink* unknown = ((MessageHeader *)self)->unknown_fields;
48
+ if (unknown != NULL) {
49
+ stringsink_uninit(unknown);
50
+ free(unknown);
51
+ }
47
52
  xfree(self);
48
53
  }
49
54
 
@@ -67,12 +72,14 @@ VALUE Message_alloc(VALUE klass) {
67
72
  msg->descriptor = desc;
68
73
  rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
69
74
 
75
+ msg->unknown_fields = NULL;
76
+
70
77
  layout_init(desc->layout, Message_data(msg));
71
78
 
72
79
  return ret;
73
80
  }
74
81
 
75
- static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
82
+ static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
76
83
  upb_oneof_iter it;
77
84
  size_t case_ofs;
78
85
  uint32_t oneof_case;
@@ -81,7 +88,7 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
81
88
 
82
89
  // If no fields in the oneof, always nil.
83
90
  if (upb_oneofdef_numfields(o) == 0) {
84
- return Qnil;
91
+ return NULL;
85
92
  }
86
93
  // Grab the first field in the oneof so we can get its layout info to find the
87
94
  // oneof_case field.
@@ -96,22 +103,165 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
96
103
  oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
97
104
 
98
105
  if (oneof_case == ONEOF_CASE_NONE) {
99
- return Qnil;
106
+ return NULL;
100
107
  }
101
108
 
102
109
  // oneof_case is a field index, so find that field.
103
110
  f = upb_oneofdef_itof(o, oneof_case);
104
111
  assert(f != NULL);
105
112
 
106
- return ID2SYM(rb_intern(upb_fielddef_name(f)));
113
+ return f;
114
+ }
115
+
116
+ enum {
117
+ METHOD_UNKNOWN = 0,
118
+ METHOD_GETTER = 1,
119
+ METHOD_SETTER = 2,
120
+ METHOD_CLEAR = 3,
121
+ METHOD_PRESENCE = 4,
122
+ METHOD_ENUM_GETTER = 5,
123
+ METHOD_WRAPPER_GETTER = 6,
124
+ METHOD_WRAPPER_SETTER = 7
125
+ };
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
+
153
+ static int extract_method_call(VALUE method_name, MessageHeader* self,
154
+ const upb_fielddef **f, const upb_oneofdef **o) {
155
+ Check_Type(method_name, T_SYMBOL);
156
+
157
+ VALUE method_str = rb_id2str(SYM2ID(method_name));
158
+ char* name = RSTRING_PTR(method_str);
159
+ size_t name_len = RSTRING_LEN(method_str);
160
+ int accessor_type;
161
+ const upb_oneofdef* test_o;
162
+ const upb_fielddef* test_f;
163
+
164
+ if (name[name_len - 1] == '=') {
165
+ accessor_type = METHOD_SETTER;
166
+ name_len--;
167
+ // We want to ensure if the proto has something named clear_foo or has_foo?,
168
+ // we don't strip the prefix.
169
+ } else if (strncmp("clear_", name, 6) == 0 &&
170
+ !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
171
+ &test_f, &test_o)) {
172
+ accessor_type = METHOD_CLEAR;
173
+ name = name + 6;
174
+ name_len = name_len - 6;
175
+ } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
176
+ !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
177
+ &test_f, &test_o)) {
178
+ accessor_type = METHOD_PRESENCE;
179
+ name = name + 4;
180
+ name_len = name_len - 5;
181
+ } else {
182
+ accessor_type = METHOD_GETTER;
183
+ }
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
+
239
+ // Verify the name corresponds to a oneof or field in this message.
240
+ if (!has_field) {
241
+ return METHOD_UNKNOWN;
242
+ }
243
+
244
+ // Method calls like 'has_foo?' are not allowed if field "foo" does not have
245
+ // a hasbit (e.g. repeated fields or non-message type fields for proto3
246
+ // syntax).
247
+ if (accessor_type == METHOD_PRESENCE && test_f != NULL &&
248
+ !upb_fielddef_haspresence(test_f)) {
249
+ return METHOD_UNKNOWN;
250
+ }
251
+
252
+ *o = test_o;
253
+ *f = test_f;
254
+ return accessor_type;
107
255
  }
108
256
 
109
257
  /*
110
258
  * call-seq:
111
259
  * Message.method_missing(*args)
112
260
  *
113
- * Provides accessors and setters for message fields according to their field
114
- * names. For any field whose name does not conflict with a built-in method, an
261
+ * Provides accessors and setters and methods to clear and check for presence of
262
+ * message fields according to their field names.
263
+ *
264
+ * For any field whose name does not conflict with a built-in method, an
115
265
  * accessor is provided with the same name as the field, and a setter is
116
266
  * provided with the name of the field plus the '=' suffix. Thus, given a
117
267
  * message instance 'msg' with field 'foo', the following code is valid:
@@ -122,13 +272,17 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
122
272
  * This method also provides read-only accessors for oneofs. If a oneof exists
123
273
  * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
124
274
  * the name of the field in that oneof that is currently set, or nil if none.
275
+ *
276
+ * It also provides methods of the form 'clear_fieldname' to clear the value
277
+ * of the field 'fieldname'. For basic data types, this will set the default
278
+ * value of the field.
279
+ *
280
+ * Additionally, it provides methods of the form 'has_fieldname?', which returns
281
+ * true if the field 'fieldname' is set in the message object, else false. For
282
+ * 'proto3' syntax, calling this for a basic type field will result in an error.
125
283
  */
126
284
  VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
127
285
  MessageHeader* self;
128
- VALUE method_name, method_str;
129
- char* name;
130
- size_t name_len;
131
- bool setter;
132
286
  const upb_oneofdef* o;
133
287
  const upb_fielddef* f;
134
288
 
@@ -136,54 +290,84 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
136
290
  if (argc < 1) {
137
291
  rb_raise(rb_eArgError, "Expected method name as first argument.");
138
292
  }
139
- method_name = argv[0];
140
- if (!SYMBOL_P(method_name)) {
141
- rb_raise(rb_eArgError, "Expected symbol as method name.");
142
- }
143
- method_str = rb_id2str(SYM2ID(method_name));
144
- name = RSTRING_PTR(method_str);
145
- name_len = RSTRING_LEN(method_str);
146
- setter = false;
147
293
 
148
- // Setters have names that end in '='.
149
- if (name[name_len - 1] == '=') {
150
- setter = true;
151
- name_len--;
152
- }
153
-
154
- // See if this name corresponds to either a oneof or field in this message.
155
- if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
156
- &o)) {
294
+ int accessor_type = extract_method_call(argv[0], self, &f, &o);
295
+ if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
157
296
  return rb_call_super(argc, argv);
297
+ } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
298
+ if (argc != 2) {
299
+ rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
300
+ }
301
+ rb_check_frozen(_self);
302
+ } else if (argc != 1) {
303
+ rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
158
304
  }
159
305
 
306
+ // Return which of the oneof fields are set
160
307
  if (o != NULL) {
161
- // This is a oneof -- return which field inside the oneof is set.
162
- if (setter) {
308
+ if (accessor_type == METHOD_SETTER) {
163
309
  rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
164
310
  }
165
- return which_oneof_field(self, o);
166
- } else {
167
- // This is a field -- get or set the field's value.
168
- assert(f);
169
- if (setter) {
170
- if (argc < 2) {
171
- rb_raise(rb_eArgError, "No value provided to setter.");
311
+
312
+ const upb_fielddef* oneof_field = which_oneof_field(self, o);
313
+ if (accessor_type == METHOD_PRESENCE) {
314
+ return oneof_field == NULL ? Qfalse : Qtrue;
315
+ } else if (accessor_type == METHOD_CLEAR) {
316
+ if (oneof_field != NULL) {
317
+ layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
172
318
  }
173
- layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
174
319
  return Qnil;
175
320
  } else {
176
- return layout_get(self->descriptor->layout, Message_data(self), f);
321
+ // METHOD_ACCESSOR
322
+ return oneof_field == NULL ? Qnil :
323
+ ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
324
+ }
325
+ // Otherwise we're operating on a single proto field
326
+ } else if (accessor_type == METHOD_SETTER) {
327
+ layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
328
+ return Qnil;
329
+ } else if (accessor_type == METHOD_CLEAR) {
330
+ layout_clear(self->descriptor->layout, Message_data(self), f);
331
+ return Qnil;
332
+ } else if (accessor_type == METHOD_PRESENCE) {
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);
177
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);
363
+ } else {
364
+ return layout_get(self->descriptor->layout, Message_data(self), f);
178
365
  }
179
366
  }
180
367
 
368
+
181
369
  VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
182
370
  MessageHeader* self;
183
- VALUE method_name, method_str;
184
- char* name;
185
- size_t name_len;
186
- bool setter;
187
371
  const upb_oneofdef* o;
188
372
  const upb_fielddef* f;
189
373
 
@@ -191,58 +375,60 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
191
375
  if (argc < 1) {
192
376
  rb_raise(rb_eArgError, "Expected method name as first argument.");
193
377
  }
194
- method_name = argv[0];
195
- if (!SYMBOL_P(method_name)) {
196
- rb_raise(rb_eArgError, "Expected symbol as method name.");
197
- }
198
- method_str = rb_id2str(SYM2ID(method_name));
199
- name = RSTRING_PTR(method_str);
200
- name_len = RSTRING_LEN(method_str);
201
- setter = false;
202
378
 
203
- // Setters have names that end in '='.
204
- if (name[name_len - 1] == '=') {
205
- setter = true;
206
- name_len--;
207
- }
208
-
209
- // See if this name corresponds to either a oneof or field in this message.
210
- if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
211
- &o)) {
379
+ int accessor_type = extract_method_call(argv[0], self, &f, &o);
380
+ if (accessor_type == METHOD_UNKNOWN) {
212
381
  return rb_call_super(argc, argv);
382
+ } else if (o != NULL) {
383
+ return accessor_type == METHOD_SETTER ? Qfalse : Qtrue;
384
+ } else {
385
+ return Qtrue;
213
386
  }
214
- if (o != NULL) {
215
- return setter ? Qfalse : Qtrue;
216
- }
217
- return Qtrue;
387
+ }
388
+
389
+ VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
390
+ const upb_def *d = upb_fielddef_subdef(f);
391
+ assert(d != NULL);
392
+
393
+ VALUE descriptor = get_def_obj(d);
394
+ VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
395
+
396
+ VALUE args[1] = { hash };
397
+ return rb_class_new_instance(1, args, msgclass);
218
398
  }
219
399
 
220
400
  int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
221
401
  MessageHeader* self;
222
- VALUE method_str;
223
- char* name;
402
+ char *name;
224
403
  const upb_fielddef* f;
225
404
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
226
405
 
227
- if (!SYMBOL_P(key)) {
406
+ if (TYPE(key) == T_STRING) {
407
+ name = RSTRING_PTR(key);
408
+ } else if (TYPE(key) == T_SYMBOL) {
409
+ name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
410
+ } else {
228
411
  rb_raise(rb_eArgError,
229
- "Expected symbols as hash keys in initialization map.");
412
+ "Expected string or symbols as hash keys when initializing proto from hash.");
230
413
  }
231
414
 
232
- method_str = rb_id2str(SYM2ID(key));
233
- name = RSTRING_PTR(method_str);
234
415
  f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
235
416
  if (f == NULL) {
236
417
  rb_raise(rb_eArgError,
237
418
  "Unknown field name '%s' in initialization map entry.", name);
238
419
  }
239
420
 
421
+ if (TYPE(val) == T_NIL) {
422
+ return 0;
423
+ }
424
+
240
425
  if (is_map_field(f)) {
241
426
  VALUE map;
242
427
 
243
428
  if (TYPE(val) != T_HASH) {
244
429
  rb_raise(rb_eArgError,
245
- "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)));
246
432
  }
247
433
  map = layout_get(self->descriptor->layout, Message_data(self), f);
248
434
  Map_merge_into_self(map, val);
@@ -251,13 +437,23 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
251
437
 
252
438
  if (TYPE(val) != T_ARRAY) {
253
439
  rb_raise(rb_eArgError,
254
- "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)));
255
442
  }
256
443
  ary = layout_get(self->descriptor->layout, Message_data(self), f);
257
444
  for (int i = 0; i < RARRAY_LEN(val); i++) {
258
- RepeatedField_push(ary, rb_ary_entry(val, i));
445
+ VALUE entry = rb_ary_entry(val, i);
446
+ if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
447
+ entry = create_submsg_from_hash(f, entry);
448
+ }
449
+
450
+ RepeatedField_push(ary, entry);
259
451
  }
260
452
  } else {
453
+ if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
454
+ val = create_submsg_from_hash(f, val);
455
+ }
456
+
261
457
  layout_set(self->descriptor->layout, Message_data(self), f, val);
262
458
  }
263
459
  return 0;
@@ -394,7 +590,12 @@ VALUE Message_inspect(VALUE _self) {
394
590
  return str;
395
591
  }
396
592
 
397
-
593
+ /*
594
+ * call-seq:
595
+ * Message.to_h => {}
596
+ *
597
+ * Returns the message as a Ruby Hash object, with keys as symbols.
598
+ */
398
599
  VALUE Message_to_h(VALUE _self) {
399
600
  MessageHeader* self;
400
601
  VALUE hash;
@@ -407,11 +608,36 @@ VALUE Message_to_h(VALUE _self) {
407
608
  !upb_msg_field_done(&it);
408
609
  upb_msg_field_next(&it)) {
409
610
  const upb_fielddef* field = upb_msg_iter_field(&it);
611
+
612
+ // For proto2, do not include fields which are not set.
613
+ if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
614
+ field_contains_hasbit(self->descriptor->layout, field) &&
615
+ !layout_has(self->descriptor->layout, Message_data(self), field)) {
616
+ continue;
617
+ }
618
+
410
619
  VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
411
620
  field);
412
621
  VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
413
- if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
622
+ if (is_map_field(field)) {
623
+ msg_value = Map_to_h(msg_value);
624
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
414
625
  msg_value = RepeatedField_to_ary(msg_value);
626
+ if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
627
+ RARRAY_LEN(msg_value) == 0) {
628
+ continue;
629
+ }
630
+
631
+ if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
632
+ for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
633
+ VALUE elem = rb_ary_entry(msg_value, i);
634
+ rb_ary_store(msg_value, i, Message_to_h(elem));
635
+ }
636
+ }
637
+
638
+ } else if (msg_value != Qnil &&
639
+ upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
640
+ msg_value = Message_to_h(msg_value);
415
641
  }
416
642
  rb_hash_aset(hash, msg_key, msg_value);
417
643
  }
@@ -495,9 +721,9 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
495
721
  get_def_obj(desc->msgdef));
496
722
  rb_define_alloc_func(klass, Message_alloc);
497
723
  rb_require("google/protobuf/message_exts");
498
- rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
724
+ rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
499
725
  rb_extend_object(
500
- klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
726
+ klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
501
727
 
502
728
  rb_define_method(klass, "method_missing",
503
729
  Message_method_missing, -1);
@@ -508,15 +734,16 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
508
734
  // Also define #clone so that we don't inherit Object#clone.
509
735
  rb_define_method(klass, "clone", Message_dup, 0);
510
736
  rb_define_method(klass, "==", Message_eq, 1);
737
+ rb_define_method(klass, "eql?", Message_eq, 1);
511
738
  rb_define_method(klass, "hash", Message_hash, 0);
512
739
  rb_define_method(klass, "to_h", Message_to_h, 0);
513
- rb_define_method(klass, "to_hash", Message_to_h, 0);
514
740
  rb_define_method(klass, "inspect", Message_inspect, 0);
741
+ rb_define_method(klass, "to_s", Message_inspect, 0);
515
742
  rb_define_method(klass, "[]", Message_index, 1);
516
743
  rb_define_method(klass, "[]=", Message_index_set, 2);
517
744
  rb_define_singleton_method(klass, "decode", Message_decode, 1);
518
745
  rb_define_singleton_method(klass, "encode", Message_encode, 1);
519
- rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
746
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
520
747
  rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
521
748
  rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
522
749
 
@@ -586,10 +813,9 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
586
813
  const char* name = upb_enum_iter_name(&it);
587
814
  int32_t value = upb_enum_iter_number(&it);
588
815
  if (name[0] < 'A' || name[0] > 'Z') {
589
- rb_raise(rb_eTypeError,
590
- "Enum value '%s' does not start with an uppercase letter "
591
- "as is required for Ruby constants.",
592
- name);
816
+ rb_warn("Enum value '%s' does not start with an uppercase letter "
817
+ "as is required for Ruby constants.",
818
+ name);
593
819
  }
594
820
  rb_define_const(mod, name, INT2NUM(value));
595
821
  }