google-protobuf 3.6.1 → 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.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/defs.c +553 -70
- data/ext/google/protobuf_c/encode_decode.c +281 -66
- data/ext/google/protobuf_c/extconf.rb +5 -1
- data/ext/google/protobuf_c/map.c +8 -3
- data/ext/google/protobuf_c/message.c +253 -72
- data/ext/google/protobuf_c/protobuf.c +4 -0
- data/ext/google/protobuf_c/protobuf.h +67 -5
- data/ext/google/protobuf_c/repeated_field.c +9 -3
- data/ext/google/protobuf_c/storage.c +265 -115
- data/ext/google/protobuf_c/upb.c +4329 -1745
- data/ext/google/protobuf_c/upb.h +2190 -518
- data/ext/google/protobuf_c/wrap_memcpy.c +1 -1
- data/lib/google/protobuf.rb +3 -2
- data/lib/google/protobuf/any_pb.rb +5 -3
- data/lib/google/protobuf/api_pb.rb +23 -21
- data/lib/google/protobuf/duration_pb.rb +5 -3
- data/lib/google/protobuf/empty_pb.rb +3 -1
- data/lib/google/protobuf/field_mask_pb.rb +4 -2
- data/lib/google/protobuf/repeated_field.rb +1 -1
- data/lib/google/protobuf/source_context_pb.rb +4 -2
- data/lib/google/protobuf/struct_pb.rb +19 -17
- data/lib/google/protobuf/timestamp_pb.rb +5 -3
- data/lib/google/protobuf/type_pb.rb +68 -66
- data/lib/google/protobuf/well_known_types.rb +12 -0
- data/lib/google/protobuf/wrappers_pb.rb +28 -26
- data/tests/basic.rb +174 -1192
- data/tests/generated_code_test.rb +5 -3
- metadata +4 -5
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'mkmf'
|
4
4
|
|
5
|
-
|
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
|
6
10
|
$CFLAGS += " -std=c99 -O3 -DNDEBUG"
|
7
11
|
end
|
8
12
|
|
data/ext/google/protobuf_c/map.c
CHANGED
@@ -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
|
@@ -841,7 +847,6 @@ void Map_register(VALUE module) {
|
|
841
847
|
rb_define_method(klass, "dup", Map_dup, 0);
|
842
848
|
rb_define_method(klass, "==", Map_eq, 1);
|
843
849
|
rb_define_method(klass, "hash", Map_hash, 0);
|
844
|
-
rb_define_method(klass, "to_hash", Map_to_h, 0);
|
845
850
|
rb_define_method(klass, "to_h", Map_to_h, 0);
|
846
851
|
rb_define_method(klass, "inspect", Map_inspect, 0);
|
847
852
|
rb_define_method(klass, "merge", Map_merge, 1);
|
@@ -79,7 +79,7 @@ VALUE Message_alloc(VALUE klass) {
|
|
79
79
|
return ret;
|
80
80
|
}
|
81
81
|
|
82
|
-
static
|
82
|
+
static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
83
83
|
upb_oneof_iter it;
|
84
84
|
size_t case_ofs;
|
85
85
|
uint32_t oneof_case;
|
@@ -88,7 +88,7 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
|
88
88
|
|
89
89
|
// If no fields in the oneof, always nil.
|
90
90
|
if (upb_oneofdef_numfields(o) == 0) {
|
91
|
-
return
|
91
|
+
return NULL;
|
92
92
|
}
|
93
93
|
// Grab the first field in the oneof so we can get its layout info to find the
|
94
94
|
// oneof_case field.
|
@@ -103,22 +103,165 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
|
103
103
|
oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
|
104
104
|
|
105
105
|
if (oneof_case == ONEOF_CASE_NONE) {
|
106
|
-
return
|
106
|
+
return NULL;
|
107
107
|
}
|
108
108
|
|
109
109
|
// oneof_case is a field index, so find that field.
|
110
110
|
f = upb_oneofdef_itof(o, oneof_case);
|
111
111
|
assert(f != NULL);
|
112
112
|
|
113
|
-
return
|
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;
|
114
255
|
}
|
115
256
|
|
116
257
|
/*
|
117
258
|
* call-seq:
|
118
259
|
* Message.method_missing(*args)
|
119
260
|
*
|
120
|
-
* Provides accessors and setters
|
121
|
-
*
|
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
|
122
265
|
* accessor is provided with the same name as the field, and a setter is
|
123
266
|
* provided with the name of the field plus the '=' suffix. Thus, given a
|
124
267
|
* message instance 'msg' with field 'foo', the following code is valid:
|
@@ -129,13 +272,17 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
|
129
272
|
* This method also provides read-only accessors for oneofs. If a oneof exists
|
130
273
|
* with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
|
131
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.
|
132
283
|
*/
|
133
284
|
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
134
285
|
MessageHeader* self;
|
135
|
-
VALUE method_name, method_str;
|
136
|
-
char* name;
|
137
|
-
size_t name_len;
|
138
|
-
bool setter;
|
139
286
|
const upb_oneofdef* o;
|
140
287
|
const upb_fielddef* f;
|
141
288
|
|
@@ -143,54 +290,84 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
143
290
|
if (argc < 1) {
|
144
291
|
rb_raise(rb_eArgError, "Expected method name as first argument.");
|
145
292
|
}
|
146
|
-
method_name = argv[0];
|
147
|
-
if (!SYMBOL_P(method_name)) {
|
148
|
-
rb_raise(rb_eArgError, "Expected symbol as method name.");
|
149
|
-
}
|
150
|
-
method_str = rb_id2str(SYM2ID(method_name));
|
151
|
-
name = RSTRING_PTR(method_str);
|
152
|
-
name_len = RSTRING_LEN(method_str);
|
153
|
-
setter = false;
|
154
|
-
|
155
|
-
// Setters have names that end in '='.
|
156
|
-
if (name[name_len - 1] == '=') {
|
157
|
-
setter = true;
|
158
|
-
name_len--;
|
159
|
-
}
|
160
293
|
|
161
|
-
|
162
|
-
if (
|
163
|
-
&o)) {
|
294
|
+
int accessor_type = extract_method_call(argv[0], self, &f, &o);
|
295
|
+
if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
|
164
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);
|
165
304
|
}
|
166
305
|
|
306
|
+
// Return which of the oneof fields are set
|
167
307
|
if (o != NULL) {
|
168
|
-
|
169
|
-
if (setter) {
|
308
|
+
if (accessor_type == METHOD_SETTER) {
|
170
309
|
rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
|
171
310
|
}
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
if (
|
177
|
-
if (
|
178
|
-
|
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);
|
179
318
|
}
|
180
|
-
layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
|
181
319
|
return Qnil;
|
182
320
|
} else {
|
183
|
-
|
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);
|
184
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);
|
185
365
|
}
|
186
366
|
}
|
187
367
|
|
368
|
+
|
188
369
|
VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
|
189
370
|
MessageHeader* self;
|
190
|
-
VALUE method_name, method_str;
|
191
|
-
char* name;
|
192
|
-
size_t name_len;
|
193
|
-
bool setter;
|
194
371
|
const upb_oneofdef* o;
|
195
372
|
const upb_fielddef* f;
|
196
373
|
|
@@ -198,30 +375,15 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
|
|
198
375
|
if (argc < 1) {
|
199
376
|
rb_raise(rb_eArgError, "Expected method name as first argument.");
|
200
377
|
}
|
201
|
-
method_name = argv[0];
|
202
|
-
if (!SYMBOL_P(method_name)) {
|
203
|
-
rb_raise(rb_eArgError, "Expected symbol as method name.");
|
204
|
-
}
|
205
|
-
method_str = rb_id2str(SYM2ID(method_name));
|
206
|
-
name = RSTRING_PTR(method_str);
|
207
|
-
name_len = RSTRING_LEN(method_str);
|
208
|
-
setter = false;
|
209
|
-
|
210
|
-
// Setters have names that end in '='.
|
211
|
-
if (name[name_len - 1] == '=') {
|
212
|
-
setter = true;
|
213
|
-
name_len--;
|
214
|
-
}
|
215
378
|
|
216
|
-
|
217
|
-
if (
|
218
|
-
&o)) {
|
379
|
+
int accessor_type = extract_method_call(argv[0], self, &f, &o);
|
380
|
+
if (accessor_type == METHOD_UNKNOWN) {
|
219
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;
|
220
386
|
}
|
221
|
-
if (o != NULL) {
|
222
|
-
return setter ? Qfalse : Qtrue;
|
223
|
-
}
|
224
|
-
return Qtrue;
|
225
387
|
}
|
226
388
|
|
227
389
|
VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
|
@@ -256,12 +418,17 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
|
256
418
|
"Unknown field name '%s' in initialization map entry.", name);
|
257
419
|
}
|
258
420
|
|
421
|
+
if (TYPE(val) == T_NIL) {
|
422
|
+
return 0;
|
423
|
+
}
|
424
|
+
|
259
425
|
if (is_map_field(f)) {
|
260
426
|
VALUE map;
|
261
427
|
|
262
428
|
if (TYPE(val) != T_HASH) {
|
263
429
|
rb_raise(rb_eArgError,
|
264
|
-
"Expected Hash object as initializer value for map field '%s'.",
|
430
|
+
"Expected Hash object as initializer value for map field '%s' (given %s).",
|
431
|
+
name, rb_class2name(CLASS_OF(val)));
|
265
432
|
}
|
266
433
|
map = layout_get(self->descriptor->layout, Message_data(self), f);
|
267
434
|
Map_merge_into_self(map, val);
|
@@ -270,7 +437,8 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
|
270
437
|
|
271
438
|
if (TYPE(val) != T_ARRAY) {
|
272
439
|
rb_raise(rb_eArgError,
|
273
|
-
"Expected array as initializer value for repeated field '%s'.",
|
440
|
+
"Expected array as initializer value for repeated field '%s' (given %s).",
|
441
|
+
name, rb_class2name(CLASS_OF(val)));
|
274
442
|
}
|
275
443
|
ary = layout_get(self->descriptor->layout, Message_data(self), f);
|
276
444
|
for (int i = 0; i < RARRAY_LEN(val); i++) {
|
@@ -440,13 +608,25 @@ VALUE Message_to_h(VALUE _self) {
|
|
440
608
|
!upb_msg_field_done(&it);
|
441
609
|
upb_msg_field_next(&it)) {
|
442
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
|
+
|
443
619
|
VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
|
444
620
|
field);
|
445
621
|
VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
|
446
|
-
if (
|
622
|
+
if (is_map_field(field)) {
|
447
623
|
msg_value = Map_to_h(msg_value);
|
448
624
|
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
449
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
|
+
}
|
450
630
|
|
451
631
|
if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
|
452
632
|
for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
|
@@ -454,6 +634,7 @@ VALUE Message_to_h(VALUE _self) {
|
|
454
634
|
rb_ary_store(msg_value, i, Message_to_h(elem));
|
455
635
|
}
|
456
636
|
}
|
637
|
+
|
457
638
|
} else if (msg_value != Qnil &&
|
458
639
|
upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
|
459
640
|
msg_value = Message_to_h(msg_value);
|
@@ -553,15 +734,16 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
553
734
|
// Also define #clone so that we don't inherit Object#clone.
|
554
735
|
rb_define_method(klass, "clone", Message_dup, 0);
|
555
736
|
rb_define_method(klass, "==", Message_eq, 1);
|
737
|
+
rb_define_method(klass, "eql?", Message_eq, 1);
|
556
738
|
rb_define_method(klass, "hash", Message_hash, 0);
|
557
739
|
rb_define_method(klass, "to_h", Message_to_h, 0);
|
558
|
-
rb_define_method(klass, "to_hash", Message_to_h, 0);
|
559
740
|
rb_define_method(klass, "inspect", Message_inspect, 0);
|
741
|
+
rb_define_method(klass, "to_s", Message_inspect, 0);
|
560
742
|
rb_define_method(klass, "[]", Message_index, 1);
|
561
743
|
rb_define_method(klass, "[]=", Message_index_set, 2);
|
562
744
|
rb_define_singleton_method(klass, "decode", Message_decode, 1);
|
563
745
|
rb_define_singleton_method(klass, "encode", Message_encode, 1);
|
564
|
-
rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
|
746
|
+
rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
|
565
747
|
rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
|
566
748
|
rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
|
567
749
|
|
@@ -631,10 +813,9 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
|
|
631
813
|
const char* name = upb_enum_iter_name(&it);
|
632
814
|
int32_t value = upb_enum_iter_number(&it);
|
633
815
|
if (name[0] < 'A' || name[0] > 'Z') {
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
name);
|
816
|
+
rb_warn("Enum value '%s' does not start with an uppercase letter "
|
817
|
+
"as is required for Ruby constants.",
|
818
|
+
name);
|
638
819
|
}
|
639
820
|
rb_define_const(mod, name, INT2NUM(value));
|
640
821
|
}
|