google-protobuf 3.2.0 → 3.9.1

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.

@@ -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
  }