google-protobuf 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of google-protobuf might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/defs.c +7 -7
- data/ext/google/protobuf_c/encode_decode.c +41 -1
- data/ext/google/protobuf_c/map.c +8 -2
- data/ext/google/protobuf_c/message.c +124 -8
- data/ext/google/protobuf_c/protobuf.h +5 -3
- data/ext/google/protobuf_c/repeated_field.c +9 -3
- data/ext/google/protobuf_c/storage.c +66 -23
- data/ext/google/protobuf_c/upb.c +478 -316
- data/ext/google/protobuf_c/upb.h +1390 -504
- data/tests/basic.rb +22 -2
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acc61dfa5ec7487b0b62edbf098aca5a5d0ce33145cbab091a892f1ed9f240cf
|
4
|
+
data.tar.gz: f7666d31441737c415008dfa0077657b8afb3c23fd0966f972b305163ffd2a02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 &&
|
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
|
}
|
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
|
@@ -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 (!
|
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
|
-
|
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
|
-
|
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'.",
|
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'.",
|
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(
|
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(
|
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",
|
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(
|
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(
|
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
|
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
|
-
|
172
|
-
|
173
|
-
|
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(
|
662
|
-
|
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(
|
831
|
-
|
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 !=
|