google-protobuf 3.6.1 → 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.
- 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
@@ -100,24 +100,34 @@ void stringsink_uninit(stringsink *sink) {
|
|
100
100
|
|
101
101
|
#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
103
|
+
typedef struct {
|
104
|
+
size_t ofs;
|
105
|
+
int32_t hasbit;
|
106
|
+
} field_handlerdata_t;
|
107
|
+
|
108
|
+
// Creates a handlerdata that contains the offset and the hasbit for the field
|
109
|
+
static const void* newhandlerdata(upb_handlers* h, uint32_t ofs, int32_t hasbit) {
|
110
|
+
field_handlerdata_t *hd = ALLOC(field_handlerdata_t);
|
111
|
+
hd->ofs = ofs;
|
112
|
+
hd->hasbit = hasbit;
|
113
|
+
upb_handlers_addcleanup(h, hd, xfree);
|
114
|
+
return hd;
|
109
115
|
}
|
110
116
|
|
111
117
|
typedef struct {
|
112
118
|
size_t ofs;
|
119
|
+
int32_t hasbit;
|
113
120
|
const upb_msgdef *md;
|
114
121
|
} submsg_handlerdata_t;
|
115
122
|
|
116
123
|
// Creates a handlerdata that contains offset and submessage type information.
|
117
|
-
static const void *newsubmsghandlerdata(upb_handlers* h,
|
124
|
+
static const void *newsubmsghandlerdata(upb_handlers* h,
|
125
|
+
uint32_t ofs,
|
126
|
+
int32_t hasbit,
|
118
127
|
const upb_fielddef* f) {
|
119
128
|
submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
|
120
129
|
hd->ofs = ofs;
|
130
|
+
hd->hasbit = hasbit;
|
121
131
|
hd->md = upb_fielddef_msgsubdef(f);
|
122
132
|
upb_handlers_addcleanup(h, hd, xfree);
|
123
133
|
return hd;
|
@@ -189,6 +199,13 @@ static void* appendstr_handler(void *closure,
|
|
189
199
|
return (void*)str;
|
190
200
|
}
|
191
201
|
|
202
|
+
static void set_hasbit(void *closure, int32_t hasbit) {
|
203
|
+
if (hasbit > 0) {
|
204
|
+
uint8_t* storage = closure;
|
205
|
+
storage[hasbit/8] |= 1 << (hasbit % 8);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
192
209
|
// Appends a 'bytes' string to a repeated field.
|
193
210
|
static void* appendbytes_handler(void *closure,
|
194
211
|
const void *hd,
|
@@ -205,10 +222,12 @@ static void* str_handler(void *closure,
|
|
205
222
|
const void *hd,
|
206
223
|
size_t size_hint) {
|
207
224
|
MessageHeader* msg = closure;
|
208
|
-
const
|
225
|
+
const field_handlerdata_t *fieldhandler = hd;
|
226
|
+
|
209
227
|
VALUE str = rb_str_new2("");
|
210
228
|
rb_enc_associate(str, kRubyStringUtf8Encoding);
|
211
|
-
DEREF(msg,
|
229
|
+
DEREF(msg, fieldhandler->ofs, VALUE) = str;
|
230
|
+
set_hasbit(closure, fieldhandler->hasbit);
|
212
231
|
return (void*)str;
|
213
232
|
}
|
214
233
|
|
@@ -217,10 +236,12 @@ static void* bytes_handler(void *closure,
|
|
217
236
|
const void *hd,
|
218
237
|
size_t size_hint) {
|
219
238
|
MessageHeader* msg = closure;
|
220
|
-
const
|
239
|
+
const field_handlerdata_t *fieldhandler = hd;
|
240
|
+
|
221
241
|
VALUE str = rb_str_new2("");
|
222
242
|
rb_enc_associate(str, kRubyString8bitEncoding);
|
223
|
-
DEREF(msg,
|
243
|
+
DEREF(msg, fieldhandler->ofs, VALUE) = str;
|
244
|
+
set_hasbit(closure, fieldhandler->hasbit);
|
224
245
|
return (void*)str;
|
225
246
|
}
|
226
247
|
|
@@ -233,18 +254,13 @@ static size_t stringdata_handler(void* closure, const void* hd,
|
|
233
254
|
}
|
234
255
|
|
235
256
|
static bool stringdata_end_handler(void* closure, const void* hd) {
|
236
|
-
|
237
|
-
const size_t *ofs = hd;
|
238
|
-
VALUE rb_str = DEREF(msg, *ofs, VALUE);
|
257
|
+
VALUE rb_str = closure;
|
239
258
|
rb_obj_freeze(rb_str);
|
240
259
|
return true;
|
241
260
|
}
|
242
261
|
|
243
262
|
static bool appendstring_end_handler(void* closure, const void* hd) {
|
244
|
-
VALUE
|
245
|
-
int size = RepeatedField_size(ary);
|
246
|
-
VALUE* last = RepeatedField_index_native(ary, size - 1);
|
247
|
-
VALUE rb_str = *last;
|
263
|
+
VALUE rb_str = closure;
|
248
264
|
rb_obj_freeze(rb_str);
|
249
265
|
return true;
|
250
266
|
}
|
@@ -280,8 +296,11 @@ static void *submsg_handler(void *closure, const void *hd) {
|
|
280
296
|
rb_class_new_instance(0, NULL, subklass);
|
281
297
|
}
|
282
298
|
|
299
|
+
set_hasbit(closure, submsgdata->hasbit);
|
300
|
+
|
283
301
|
submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
|
284
302
|
TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
|
303
|
+
|
285
304
|
return submsg;
|
286
305
|
}
|
287
306
|
|
@@ -370,6 +389,9 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
|
|
370
389
|
if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
|
371
390
|
mapdata->value_field_type == UPB_TYPE_ENUM) {
|
372
391
|
value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
|
392
|
+
if (mapdata->value_field_type == UPB_TYPE_ENUM) {
|
393
|
+
value_field_typeclass = EnumDescriptor_enummodule(value_field_typeclass);
|
394
|
+
}
|
373
395
|
}
|
374
396
|
|
375
397
|
value = native_slot_get(
|
@@ -457,9 +479,8 @@ static void *oneofbytes_handler(void *closure,
|
|
457
479
|
}
|
458
480
|
|
459
481
|
static bool oneofstring_end_handler(void* closure, const void* hd) {
|
460
|
-
|
461
|
-
|
462
|
-
rb_obj_freeze(DEREF(msg, oneofdata->ofs, VALUE));
|
482
|
+
VALUE rb_str = rb_str_new2("");
|
483
|
+
rb_obj_freeze(rb_str);
|
463
484
|
return true;
|
464
485
|
}
|
465
486
|
|
@@ -500,7 +521,7 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
|
|
500
521
|
const upb_fielddef *f,
|
501
522
|
size_t offset) {
|
502
523
|
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
|
503
|
-
upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
|
524
|
+
upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset, -1));
|
504
525
|
upb_handlers_setstartseq(h, f, startseq_handler, &attr);
|
505
526
|
upb_handlerattr_uninit(&attr);
|
506
527
|
|
@@ -534,7 +555,7 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
|
|
534
555
|
}
|
535
556
|
case UPB_TYPE_MESSAGE: {
|
536
557
|
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
|
537
|
-
upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f));
|
558
|
+
upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, -1, f));
|
538
559
|
upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
|
539
560
|
upb_handlerattr_uninit(&attr);
|
540
561
|
break;
|
@@ -545,7 +566,15 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
|
|
545
566
|
// Set up handlers for a singular field.
|
546
567
|
static void add_handlers_for_singular_field(upb_handlers *h,
|
547
568
|
const upb_fielddef *f,
|
548
|
-
size_t offset
|
569
|
+
size_t offset,
|
570
|
+
size_t hasbit_off) {
|
571
|
+
// The offset we pass to UPB points to the start of the Message,
|
572
|
+
// rather than the start of where our data is stored.
|
573
|
+
int32_t hasbit = -1;
|
574
|
+
if (hasbit_off != MESSAGE_FIELD_NO_HASBIT) {
|
575
|
+
hasbit = hasbit_off + sizeof(MessageHeader) * 8;
|
576
|
+
}
|
577
|
+
|
549
578
|
switch (upb_fielddef_type(f)) {
|
550
579
|
case UPB_TYPE_BOOL:
|
551
580
|
case UPB_TYPE_INT32:
|
@@ -555,13 +584,13 @@ static void add_handlers_for_singular_field(upb_handlers *h,
|
|
555
584
|
case UPB_TYPE_INT64:
|
556
585
|
case UPB_TYPE_UINT64:
|
557
586
|
case UPB_TYPE_DOUBLE:
|
558
|
-
upb_msg_setscalarhandler(h, f, offset,
|
587
|
+
upb_msg_setscalarhandler(h, f, offset, hasbit);
|
559
588
|
break;
|
560
589
|
case UPB_TYPE_STRING:
|
561
590
|
case UPB_TYPE_BYTES: {
|
562
591
|
bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
|
563
592
|
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
|
564
|
-
upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
|
593
|
+
upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset, hasbit));
|
565
594
|
upb_handlers_setstartstr(h, f,
|
566
595
|
is_bytes ? bytes_handler : str_handler,
|
567
596
|
&attr);
|
@@ -572,7 +601,9 @@ static void add_handlers_for_singular_field(upb_handlers *h,
|
|
572
601
|
}
|
573
602
|
case UPB_TYPE_MESSAGE: {
|
574
603
|
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
|
575
|
-
upb_handlerattr_sethandlerdata(&attr,
|
604
|
+
upb_handlerattr_sethandlerdata(&attr,
|
605
|
+
newsubmsghandlerdata(h, offset,
|
606
|
+
hasbit, f));
|
576
607
|
upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
|
577
608
|
upb_handlerattr_uninit(&attr);
|
578
609
|
break;
|
@@ -610,10 +641,12 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
|
|
610
641
|
|
611
642
|
add_handlers_for_singular_field(
|
612
643
|
h, key_field,
|
613
|
-
offsetof(map_parse_frame_t, key_storage)
|
644
|
+
offsetof(map_parse_frame_t, key_storage),
|
645
|
+
MESSAGE_FIELD_NO_HASBIT);
|
614
646
|
add_handlers_for_singular_field(
|
615
647
|
h, value_field,
|
616
|
-
offsetof(map_parse_frame_t, value_storage)
|
648
|
+
offsetof(map_parse_frame_t, value_storage),
|
649
|
+
MESSAGE_FIELD_NO_HASBIT);
|
617
650
|
}
|
618
651
|
|
619
652
|
// Set up handlers for a oneof field.
|
@@ -718,7 +751,8 @@ static void add_handlers_for_message(const void *closure, upb_handlers *h) {
|
|
718
751
|
} else if (upb_fielddef_isseq(f)) {
|
719
752
|
add_handlers_for_repeated_field(h, f, offset);
|
720
753
|
} else {
|
721
|
-
add_handlers_for_singular_field(
|
754
|
+
add_handlers_for_singular_field(
|
755
|
+
h, f, offset, desc->layout->fields[upb_fielddef_index(f)].hasbit);
|
722
756
|
}
|
723
757
|
}
|
724
758
|
}
|
@@ -854,19 +888,38 @@ VALUE Message_decode(VALUE klass, VALUE data) {
|
|
854
888
|
|
855
889
|
/*
|
856
890
|
* call-seq:
|
857
|
-
* MessageClass.decode_json(data) => message
|
891
|
+
* MessageClass.decode_json(data, options = {}) => message
|
858
892
|
*
|
859
893
|
* Decodes the given data (as a string containing bytes in protocol buffers wire
|
860
894
|
* format) under the interpretration given by this message class's definition
|
861
895
|
* and returns a message object with the corresponding field values.
|
896
|
+
*
|
897
|
+
* @param options [Hash] options for the decoder
|
898
|
+
* ignore_unknown_fields: set true to ignore unknown fields (default is to raise an error)
|
862
899
|
*/
|
863
|
-
VALUE Message_decode_json(VALUE
|
900
|
+
VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
|
864
901
|
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
865
902
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
866
903
|
VALUE msgklass = Descriptor_msgclass(descriptor);
|
867
904
|
VALUE msg_rb;
|
905
|
+
VALUE data = argv[0];
|
906
|
+
VALUE ignore_unknown_fields = Qfalse;
|
868
907
|
MessageHeader* msg;
|
869
908
|
|
909
|
+
if (argc < 1 || argc > 2) {
|
910
|
+
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
911
|
+
}
|
912
|
+
|
913
|
+
if (argc == 2) {
|
914
|
+
VALUE hash_args = argv[1];
|
915
|
+
if (TYPE(hash_args) != T_HASH) {
|
916
|
+
rb_raise(rb_eArgError, "Expected hash arguments.");
|
917
|
+
}
|
918
|
+
|
919
|
+
ignore_unknown_fields = rb_hash_lookup2(
|
920
|
+
hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse);
|
921
|
+
}
|
922
|
+
|
870
923
|
if (TYPE(data) != T_STRING) {
|
871
924
|
rb_raise(rb_eArgError, "Expected string for JSON data.");
|
872
925
|
}
|
@@ -882,10 +935,12 @@ VALUE Message_decode_json(VALUE klass, VALUE data) {
|
|
882
935
|
stackenv se;
|
883
936
|
upb_sink sink;
|
884
937
|
upb_json_parser* parser;
|
938
|
+
DescriptorPool* pool = ruby_to_DescriptorPool(generated_pool);
|
885
939
|
stackenv_init(&se, "Error occurred during parsing: %s");
|
886
940
|
|
887
941
|
upb_sink_reset(&sink, get_fill_handlers(desc), msg);
|
888
|
-
parser = upb_json_parser_create(&se.env, method,
|
942
|
+
parser = upb_json_parser_create(&se.env, method, pool->symtab,
|
943
|
+
&sink, ignore_unknown_fields);
|
889
944
|
upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
|
890
945
|
upb_json_parser_input(parser));
|
891
946
|
|
@@ -901,13 +956,9 @@ VALUE Message_decode_json(VALUE klass, VALUE data) {
|
|
901
956
|
|
902
957
|
/* msgvisitor *****************************************************************/
|
903
958
|
|
904
|
-
// TODO: If/when we support proto2 semantics in addition to the current proto3
|
905
|
-
// semantics, which means that we have true field presence, we will want to
|
906
|
-
// modify msgvisitor so that it emits all present fields rather than all
|
907
|
-
// non-default-value fields.
|
908
|
-
|
909
959
|
static void putmsg(VALUE msg, const Descriptor* desc,
|
910
|
-
upb_sink *sink, int depth, bool emit_defaults
|
960
|
+
upb_sink *sink, int depth, bool emit_defaults,
|
961
|
+
bool is_json, bool open_msg);
|
911
962
|
|
912
963
|
static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
|
913
964
|
upb_selector_t ret;
|
@@ -939,7 +990,7 @@ static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
|
|
939
990
|
}
|
940
991
|
|
941
992
|
static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
|
942
|
-
int depth, bool emit_defaults) {
|
993
|
+
int depth, bool emit_defaults, bool is_json) {
|
943
994
|
upb_sink subsink;
|
944
995
|
VALUE descriptor;
|
945
996
|
Descriptor* subdesc;
|
@@ -950,18 +1001,22 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
|
|
950
1001
|
subdesc = ruby_to_Descriptor(descriptor);
|
951
1002
|
|
952
1003
|
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
|
953
|
-
putmsg(submsg, subdesc, &subsink, depth + 1, emit_defaults);
|
1004
|
+
putmsg(submsg, subdesc, &subsink, depth + 1, emit_defaults, is_json, true);
|
954
1005
|
upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
955
1006
|
}
|
956
1007
|
|
957
1008
|
static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
|
958
|
-
int depth, bool emit_defaults) {
|
1009
|
+
int depth, bool emit_defaults, bool is_json) {
|
959
1010
|
upb_sink subsink;
|
960
1011
|
upb_fieldtype_t type = upb_fielddef_type(f);
|
961
1012
|
upb_selector_t sel = 0;
|
962
1013
|
int size;
|
963
1014
|
|
964
1015
|
if (ary == Qnil) return;
|
1016
|
+
if (!emit_defaults && NUM2INT(RepeatedField_length(ary)) == 0) return;
|
1017
|
+
|
1018
|
+
size = NUM2INT(RepeatedField_length(ary));
|
1019
|
+
if (size == 0 && !emit_defaults) return;
|
965
1020
|
|
966
1021
|
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
967
1022
|
|
@@ -969,7 +1024,6 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
|
|
969
1024
|
sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
|
970
1025
|
}
|
971
1026
|
|
972
|
-
size = NUM2INT(RepeatedField_length(ary));
|
973
1027
|
for (int i = 0; i < size; i++) {
|
974
1028
|
void* memory = RepeatedField_index_native(ary, i);
|
975
1029
|
switch (type) {
|
@@ -992,7 +1046,8 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
|
|
992
1046
|
putstr(*((VALUE *)memory), f, &subsink);
|
993
1047
|
break;
|
994
1048
|
case UPB_TYPE_MESSAGE:
|
995
|
-
putsubmsg(*((VALUE *)memory), f, &subsink, depth,
|
1049
|
+
putsubmsg(*((VALUE *)memory), f, &subsink, depth,
|
1050
|
+
emit_defaults, is_json);
|
996
1051
|
break;
|
997
1052
|
|
998
1053
|
#undef T
|
@@ -1007,7 +1062,13 @@ static void put_ruby_value(VALUE value,
|
|
1007
1062
|
VALUE type_class,
|
1008
1063
|
int depth,
|
1009
1064
|
upb_sink *sink,
|
1010
|
-
bool emit_defaults
|
1065
|
+
bool emit_defaults,
|
1066
|
+
bool is_json) {
|
1067
|
+
if (depth > ENCODE_MAX_NESTING) {
|
1068
|
+
rb_raise(rb_eRuntimeError,
|
1069
|
+
"Maximum recursion depth exceeded during encoding.");
|
1070
|
+
}
|
1071
|
+
|
1011
1072
|
upb_selector_t sel = 0;
|
1012
1073
|
if (upb_fielddef_isprimitive(f)) {
|
1013
1074
|
sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
|
@@ -1047,12 +1108,12 @@ static void put_ruby_value(VALUE value,
|
|
1047
1108
|
putstr(value, f, sink);
|
1048
1109
|
break;
|
1049
1110
|
case UPB_TYPE_MESSAGE:
|
1050
|
-
putsubmsg(value, f, sink, depth, emit_defaults);
|
1111
|
+
putsubmsg(value, f, sink, depth, emit_defaults, is_json);
|
1051
1112
|
}
|
1052
1113
|
}
|
1053
1114
|
|
1054
1115
|
static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
|
1055
|
-
int depth, bool emit_defaults) {
|
1116
|
+
int depth, bool emit_defaults, bool is_json) {
|
1056
1117
|
Map* self;
|
1057
1118
|
upb_sink subsink;
|
1058
1119
|
const upb_fielddef* key_field;
|
@@ -1060,6 +1121,8 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
|
|
1060
1121
|
Map_iter it;
|
1061
1122
|
|
1062
1123
|
if (map == Qnil) return;
|
1124
|
+
if (!emit_defaults && Map_length(map) == 0) return;
|
1125
|
+
|
1063
1126
|
self = ruby_to_Map(map);
|
1064
1127
|
|
1065
1128
|
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
@@ -1078,9 +1141,10 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
|
|
1078
1141
|
&entry_sink);
|
1079
1142
|
upb_sink_startmsg(&entry_sink);
|
1080
1143
|
|
1081
|
-
put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink,
|
1144
|
+
put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink,
|
1145
|
+
emit_defaults, is_json);
|
1082
1146
|
put_ruby_value(value, value_field, self->value_type_class, depth + 1,
|
1083
|
-
&entry_sink, emit_defaults);
|
1147
|
+
&entry_sink, emit_defaults, is_json);
|
1084
1148
|
|
1085
1149
|
upb_sink_endmsg(&entry_sink, &status);
|
1086
1150
|
upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
@@ -1089,13 +1153,143 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
|
|
1089
1153
|
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
|
1090
1154
|
}
|
1091
1155
|
|
1156
|
+
static const upb_handlers* msgdef_json_serialize_handlers(
|
1157
|
+
Descriptor* desc, bool preserve_proto_fieldnames);
|
1158
|
+
|
1159
|
+
static void putjsonany(VALUE msg_rb, const Descriptor* desc,
|
1160
|
+
upb_sink* sink, int depth, bool emit_defaults) {
|
1161
|
+
upb_status status;
|
1162
|
+
MessageHeader* msg = NULL;
|
1163
|
+
const upb_fielddef* type_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_TYPE);
|
1164
|
+
const upb_fielddef* value_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_VALUE);
|
1165
|
+
|
1166
|
+
size_t type_url_offset;
|
1167
|
+
VALUE type_url_str_rb;
|
1168
|
+
const upb_msgdef *payload_type = NULL;
|
1169
|
+
|
1170
|
+
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
|
1171
|
+
|
1172
|
+
upb_sink_startmsg(sink);
|
1173
|
+
|
1174
|
+
/* Handle type url */
|
1175
|
+
type_url_offset = desc->layout->fields[upb_fielddef_index(type_field)].offset;
|
1176
|
+
type_url_str_rb = DEREF(Message_data(msg), type_url_offset, VALUE);
|
1177
|
+
if (RSTRING_LEN(type_url_str_rb) > 0) {
|
1178
|
+
putstr(type_url_str_rb, type_field, sink);
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
{
|
1182
|
+
const char* type_url_str = RSTRING_PTR(type_url_str_rb);
|
1183
|
+
size_t type_url_len = RSTRING_LEN(type_url_str_rb);
|
1184
|
+
DescriptorPool* pool = ruby_to_DescriptorPool(generated_pool);
|
1185
|
+
|
1186
|
+
if (type_url_len <= 20 ||
|
1187
|
+
strncmp(type_url_str, "type.googleapis.com/", 20) != 0) {
|
1188
|
+
rb_raise(rb_eRuntimeError, "Invalid type url: %s", type_url_str);
|
1189
|
+
return;
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
/* Resolve type url */
|
1193
|
+
type_url_str += 20;
|
1194
|
+
type_url_len -= 20;
|
1195
|
+
|
1196
|
+
payload_type = upb_symtab_lookupmsg2(
|
1197
|
+
pool->symtab, type_url_str, type_url_len);
|
1198
|
+
if (payload_type == NULL) {
|
1199
|
+
rb_raise(rb_eRuntimeError, "Unknown type: %s", type_url_str);
|
1200
|
+
return;
|
1201
|
+
}
|
1202
|
+
}
|
1203
|
+
|
1204
|
+
{
|
1205
|
+
uint32_t value_offset;
|
1206
|
+
VALUE value_str_rb;
|
1207
|
+
const char* value_str;
|
1208
|
+
size_t value_len;
|
1209
|
+
|
1210
|
+
value_offset = desc->layout->fields[upb_fielddef_index(value_field)].offset;
|
1211
|
+
value_str_rb = DEREF(Message_data(msg), value_offset, VALUE);
|
1212
|
+
value_str = RSTRING_PTR(value_str_rb);
|
1213
|
+
value_len = RSTRING_LEN(value_str_rb);
|
1214
|
+
|
1215
|
+
if (value_len > 0) {
|
1216
|
+
VALUE payload_desc_rb = get_def_obj(payload_type);
|
1217
|
+
Descriptor* payload_desc = ruby_to_Descriptor(payload_desc_rb);
|
1218
|
+
VALUE payload_class = Descriptor_msgclass(payload_desc_rb);
|
1219
|
+
upb_sink subsink;
|
1220
|
+
bool is_wellknown;
|
1221
|
+
|
1222
|
+
VALUE payload_msg_rb = Message_decode(payload_class, value_str_rb);
|
1223
|
+
|
1224
|
+
is_wellknown =
|
1225
|
+
upb_msgdef_wellknowntype(payload_desc->msgdef) !=
|
1226
|
+
UPB_WELLKNOWN_UNSPECIFIED;
|
1227
|
+
if (is_wellknown) {
|
1228
|
+
upb_sink_startstr(sink, getsel(value_field, UPB_HANDLER_STARTSTR), 0,
|
1229
|
+
&subsink);
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
subsink.handlers =
|
1233
|
+
msgdef_json_serialize_handlers(payload_desc, true);
|
1234
|
+
subsink.closure = sink->closure;
|
1235
|
+
putmsg(payload_msg_rb, payload_desc, &subsink, depth, emit_defaults, true,
|
1236
|
+
is_wellknown);
|
1237
|
+
}
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
upb_sink_endmsg(sink, &status);
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
static void putjsonlistvalue(
|
1244
|
+
VALUE msg_rb, const Descriptor* desc,
|
1245
|
+
upb_sink* sink, int depth, bool emit_defaults) {
|
1246
|
+
upb_status status;
|
1247
|
+
upb_sink subsink;
|
1248
|
+
MessageHeader* msg = NULL;
|
1249
|
+
const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1);
|
1250
|
+
uint32_t offset =
|
1251
|
+
desc->layout->fields[upb_fielddef_index(f)].offset +
|
1252
|
+
sizeof(MessageHeader);
|
1253
|
+
VALUE ary;
|
1254
|
+
|
1255
|
+
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
|
1256
|
+
|
1257
|
+
upb_sink_startmsg(sink);
|
1258
|
+
|
1259
|
+
ary = DEREF(msg, offset, VALUE);
|
1260
|
+
|
1261
|
+
if (ary == Qnil || RepeatedField_size(ary) == 0) {
|
1262
|
+
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
1263
|
+
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
|
1264
|
+
} else {
|
1265
|
+
putary(ary, f, sink, depth, emit_defaults, true);
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
upb_sink_endmsg(sink, &status);
|
1269
|
+
}
|
1270
|
+
|
1092
1271
|
static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
1093
|
-
upb_sink *sink, int depth, bool emit_defaults
|
1272
|
+
upb_sink *sink, int depth, bool emit_defaults,
|
1273
|
+
bool is_json, bool open_msg) {
|
1094
1274
|
MessageHeader* msg;
|
1095
1275
|
upb_msg_field_iter i;
|
1096
1276
|
upb_status status;
|
1097
1277
|
|
1098
|
-
|
1278
|
+
if (is_json &&
|
1279
|
+
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
|
1280
|
+
putjsonany(msg_rb, desc, sink, depth, emit_defaults);
|
1281
|
+
return;
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
if (is_json &&
|
1285
|
+
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_LISTVALUE) {
|
1286
|
+
putjsonlistvalue(msg_rb, desc, sink, depth, emit_defaults);
|
1287
|
+
return;
|
1288
|
+
}
|
1289
|
+
|
1290
|
+
if (open_msg) {
|
1291
|
+
upb_sink_startmsg(sink);
|
1292
|
+
}
|
1099
1293
|
|
1100
1294
|
// Protect against cycles (possible because users may freely reassign message
|
1101
1295
|
// and repeated fields) by imposing a maximum recursion depth.
|
@@ -1140,30 +1334,45 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
|
1140
1334
|
if (is_map_field(f)) {
|
1141
1335
|
VALUE map = DEREF(msg, offset, VALUE);
|
1142
1336
|
if (map != Qnil || emit_defaults) {
|
1143
|
-
putmap(map, f, sink, depth, emit_defaults);
|
1337
|
+
putmap(map, f, sink, depth, emit_defaults, is_json);
|
1144
1338
|
}
|
1145
1339
|
} else if (upb_fielddef_isseq(f)) {
|
1146
1340
|
VALUE ary = DEREF(msg, offset, VALUE);
|
1147
1341
|
if (ary != Qnil) {
|
1148
|
-
putary(ary, f, sink, depth, emit_defaults);
|
1342
|
+
putary(ary, f, sink, depth, emit_defaults, is_json);
|
1149
1343
|
}
|
1150
1344
|
} else if (upb_fielddef_isstring(f)) {
|
1151
1345
|
VALUE str = DEREF(msg, offset, VALUE);
|
1152
|
-
|
1346
|
+
bool is_default = false;
|
1347
|
+
|
1348
|
+
if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO2) {
|
1349
|
+
is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse;
|
1350
|
+
} else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) {
|
1351
|
+
is_default = RSTRING_LEN(str) == 0;
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
if (is_matching_oneof || emit_defaults || !is_default) {
|
1153
1355
|
putstr(str, f, sink);
|
1154
1356
|
}
|
1155
1357
|
} else if (upb_fielddef_issubmsg(f)) {
|
1156
|
-
putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth,
|
1358
|
+
putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth,
|
1359
|
+
emit_defaults, is_json);
|
1157
1360
|
} else {
|
1158
1361
|
upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
|
1159
1362
|
|
1160
|
-
#define T(upbtypeconst, upbtype, ctype, default_value)
|
1161
|
-
case upbtypeconst: {
|
1162
|
-
ctype value = DEREF(msg, offset, ctype);
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1363
|
+
#define T(upbtypeconst, upbtype, ctype, default_value) \
|
1364
|
+
case upbtypeconst: { \
|
1365
|
+
ctype value = DEREF(msg, offset, ctype); \
|
1366
|
+
bool is_default = false; \
|
1367
|
+
if (upb_fielddef_haspresence(f)) { \
|
1368
|
+
is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse; \
|
1369
|
+
} else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) { \
|
1370
|
+
is_default = default_value == value; \
|
1371
|
+
} \
|
1372
|
+
if (is_matching_oneof || emit_defaults || !is_default) { \
|
1373
|
+
upb_sink_put##upbtype(sink, sel, value); \
|
1374
|
+
} \
|
1375
|
+
} \
|
1167
1376
|
break;
|
1168
1377
|
|
1169
1378
|
switch (upb_fielddef_type(f)) {
|
@@ -1191,7 +1400,9 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
|
1191
1400
|
upb_sink_putunknown(sink, unknown->ptr, unknown->len);
|
1192
1401
|
}
|
1193
1402
|
|
1194
|
-
|
1403
|
+
if (open_msg) {
|
1404
|
+
upb_sink_endmsg(sink, &status);
|
1405
|
+
}
|
1195
1406
|
}
|
1196
1407
|
|
1197
1408
|
static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
|
@@ -1246,7 +1457,7 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
|
|
1246
1457
|
stackenv_init(&se, "Error occurred during encoding: %s");
|
1247
1458
|
encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
|
1248
1459
|
|
1249
|
-
putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0, false);
|
1460
|
+
putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0, false, false, true);
|
1250
1461
|
|
1251
1462
|
ret = rb_str_new(sink.ptr, sink.len);
|
1252
1463
|
|
@@ -1259,9 +1470,12 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
|
|
1259
1470
|
|
1260
1471
|
/*
|
1261
1472
|
* call-seq:
|
1262
|
-
* MessageClass.encode_json(msg) => json_string
|
1473
|
+
* MessageClass.encode_json(msg, options = {}) => json_string
|
1263
1474
|
*
|
1264
1475
|
* Encodes the given message object into its serialized JSON representation.
|
1476
|
+
* @param options [Hash] options for the decoder
|
1477
|
+
* preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase)
|
1478
|
+
* emit_defaults: set true to emit 0/false values (default is to omit them)
|
1265
1479
|
*/
|
1266
1480
|
VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
|
1267
1481
|
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
@@ -1301,7 +1515,8 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
|
|
1301
1515
|
stackenv_init(&se, "Error occurred during encoding: %s");
|
1302
1516
|
printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
|
1303
1517
|
|
1304
|
-
putmsg(msg_rb, desc, upb_json_printer_input(printer), 0,
|
1518
|
+
putmsg(msg_rb, desc, upb_json_printer_input(printer), 0,
|
1519
|
+
RTEST(emit_defaults), true, true);
|
1305
1520
|
|
1306
1521
|
ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding());
|
1307
1522
|
|