google-protobuf 3.0.0.alpha.2.0 → 3.0.0.alpha.3
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.
- data/ext/google/protobuf_c/defs.c +4 -6
- data/ext/google/protobuf_c/encode_decode.c +75 -85
- data/ext/google/protobuf_c/extconf.rb +3 -1
- data/ext/google/protobuf_c/message.c +44 -9
- data/ext/google/protobuf_c/protobuf.c +10 -7
- data/ext/google/protobuf_c/protobuf.h +9 -9
- data/ext/google/protobuf_c/repeated_field.c +95 -55
- data/ext/google/protobuf_c/storage.c +5 -2
- data/ext/google/protobuf_c/upb.c +822 -248
- data/ext/google/protobuf_c/upb.h +511 -467
- data/lib/google/protobuf.rb +33 -1
- data/lib/google/protobuf/message_exts.rb +53 -0
- data/lib/google/protobuf/repeated_field.rb +188 -0
- data/tests/basic.rb +143 -7
- data/tests/stress.rb +1 -1
- metadata +64 -12
- checksums.yaml +0 -7
@@ -34,8 +34,6 @@
|
|
34
34
|
// Common utilities.
|
35
35
|
// -----------------------------------------------------------------------------
|
36
36
|
|
37
|
-
const char* kDescriptorInstanceVar = "descriptor";
|
38
|
-
|
39
37
|
static const char* get_str(VALUE str) {
|
40
38
|
Check_Type(str, T_STRING);
|
41
39
|
return RSTRING_PTR(str);
|
@@ -250,7 +248,7 @@ void Descriptor_free(void* _self) {
|
|
250
248
|
&self->pb_serialize_handlers);
|
251
249
|
}
|
252
250
|
if (self->json_serialize_handlers) {
|
253
|
-
upb_handlers_unref(self->
|
251
|
+
upb_handlers_unref(self->json_serialize_handlers,
|
254
252
|
&self->json_serialize_handlers);
|
255
253
|
}
|
256
254
|
xfree(self);
|
@@ -1590,9 +1588,9 @@ VALUE Builder_add_message(VALUE _self, VALUE name) {
|
|
1590
1588
|
* call-seq:
|
1591
1589
|
* Builder.add_enum(name, &block)
|
1592
1590
|
*
|
1593
|
-
* Creates a new, empty enum descriptor with the given name, and invokes the
|
1594
|
-
* the context of an EnumBuilderContext on that descriptor. The block
|
1595
|
-
* call EnumBuilderContext#add_value to define the enum values.
|
1591
|
+
* Creates a new, empty enum descriptor with the given name, and invokes the
|
1592
|
+
* block in the context of an EnumBuilderContext on that descriptor. The block
|
1593
|
+
* can then call EnumBuilderContext#add_value to define the enum values.
|
1596
1594
|
*
|
1597
1595
|
* This is the recommended, idiomatic way to build enum definitions.
|
1598
1596
|
*/
|
@@ -622,6 +622,49 @@ static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
|
|
622
622
|
return desc->fill_method;
|
623
623
|
}
|
624
624
|
|
625
|
+
|
626
|
+
// Stack-allocated context during an encode/decode operation. Contains the upb
|
627
|
+
// environment and its stack-based allocator, an initial buffer for allocations
|
628
|
+
// to avoid malloc() when possible, and a template for Ruby exception messages
|
629
|
+
// if any error occurs.
|
630
|
+
#define STACK_ENV_STACKBYTES 4096
|
631
|
+
typedef struct {
|
632
|
+
upb_env env;
|
633
|
+
upb_seededalloc alloc;
|
634
|
+
const char* ruby_error_template;
|
635
|
+
char allocbuf[STACK_ENV_STACKBYTES];
|
636
|
+
} stackenv;
|
637
|
+
|
638
|
+
static void stackenv_init(stackenv* se, const char* errmsg);
|
639
|
+
static void stackenv_uninit(stackenv* se);
|
640
|
+
|
641
|
+
// Callback invoked by upb if any error occurs during parsing or serialization.
|
642
|
+
static bool env_error_func(void* ud, const upb_status* status) {
|
643
|
+
stackenv* se = ud;
|
644
|
+
// Free the env -- rb_raise will longjmp up the stack past the encode/decode
|
645
|
+
// function so it would not otherwise have been freed.
|
646
|
+
stackenv_uninit(se);
|
647
|
+
rb_raise(rb_eRuntimeError, se->ruby_error_template,
|
648
|
+
upb_status_errmsg(status));
|
649
|
+
// Never reached: rb_raise() always longjmp()s up the stack, past all of our
|
650
|
+
// code, back to Ruby.
|
651
|
+
return false;
|
652
|
+
}
|
653
|
+
|
654
|
+
static void stackenv_init(stackenv* se, const char* errmsg) {
|
655
|
+
se->ruby_error_template = errmsg;
|
656
|
+
upb_env_init(&se->env);
|
657
|
+
upb_seededalloc_init(&se->alloc, &se->allocbuf, STACK_ENV_STACKBYTES);
|
658
|
+
upb_env_setallocfunc(
|
659
|
+
&se->env, upb_seededalloc_getallocfunc(&se->alloc), &se->alloc);
|
660
|
+
upb_env_seterrorfunc(&se->env, env_error_func, se);
|
661
|
+
}
|
662
|
+
|
663
|
+
static void stackenv_uninit(stackenv* se) {
|
664
|
+
upb_env_uninit(&se->env);
|
665
|
+
upb_seededalloc_uninit(&se->alloc);
|
666
|
+
}
|
667
|
+
|
625
668
|
/*
|
626
669
|
* call-seq:
|
627
670
|
* MessageClass.decode(data) => message
|
@@ -631,7 +674,7 @@ static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
|
|
631
674
|
* and returns a message object with the corresponding field values.
|
632
675
|
*/
|
633
676
|
VALUE Message_decode(VALUE klass, VALUE data) {
|
634
|
-
VALUE descriptor =
|
677
|
+
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
635
678
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
636
679
|
VALUE msgklass = Descriptor_msgclass(descriptor);
|
637
680
|
|
@@ -645,21 +688,17 @@ VALUE Message_decode(VALUE klass, VALUE data) {
|
|
645
688
|
|
646
689
|
const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
|
647
690
|
const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
|
648
|
-
|
649
|
-
|
650
|
-
upb_status status = UPB_STATUS_INIT;
|
691
|
+
stackenv se;
|
692
|
+
stackenv_init(&se, "Error occurred during parsing: %s");
|
651
693
|
|
652
|
-
|
694
|
+
upb_sink sink;
|
653
695
|
upb_sink_reset(&sink, h, msg);
|
654
|
-
|
696
|
+
upb_pbdecoder* decoder =
|
697
|
+
upb_pbdecoder_create(&se.env, method, &sink);
|
655
698
|
upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
|
656
|
-
upb_pbdecoder_input(
|
699
|
+
upb_pbdecoder_input(decoder));
|
657
700
|
|
658
|
-
|
659
|
-
if (!upb_ok(&status)) {
|
660
|
-
rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.",
|
661
|
-
upb_status_errmsg(&status));
|
662
|
-
}
|
701
|
+
stackenv_uninit(&se);
|
663
702
|
|
664
703
|
return msg_rb;
|
665
704
|
}
|
@@ -673,7 +712,7 @@ VALUE Message_decode(VALUE klass, VALUE data) {
|
|
673
712
|
* and returns a message object with the corresponding field values.
|
674
713
|
*/
|
675
714
|
VALUE Message_decode_json(VALUE klass, VALUE data) {
|
676
|
-
VALUE descriptor =
|
715
|
+
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
677
716
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
678
717
|
VALUE msgklass = Descriptor_msgclass(descriptor);
|
679
718
|
|
@@ -688,21 +727,16 @@ VALUE Message_decode_json(VALUE klass, VALUE data) {
|
|
688
727
|
MessageHeader* msg;
|
689
728
|
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
|
690
729
|
|
691
|
-
|
692
|
-
|
693
|
-
upb_json_parser_init(&parser, &status);
|
730
|
+
stackenv se;
|
731
|
+
stackenv_init(&se, "Error occurred during parsing: %s");
|
694
732
|
|
695
733
|
upb_sink sink;
|
696
734
|
upb_sink_reset(&sink, get_fill_handlers(desc), msg);
|
697
|
-
|
735
|
+
upb_json_parser* parser = upb_json_parser_create(&se.env, &sink);
|
698
736
|
upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
|
699
|
-
upb_json_parser_input(
|
737
|
+
upb_json_parser_input(parser));
|
700
738
|
|
701
|
-
|
702
|
-
if (!upb_ok(&status)) {
|
703
|
-
rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.",
|
704
|
-
upb_status_errmsg(&status));
|
705
|
-
}
|
739
|
+
stackenv_uninit(&se);
|
706
740
|
|
707
741
|
return msg_rb;
|
708
742
|
}
|
@@ -813,7 +847,7 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
|
|
813
847
|
if (submsg == Qnil) return;
|
814
848
|
|
815
849
|
upb_sink subsink;
|
816
|
-
VALUE descriptor =
|
850
|
+
VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
|
817
851
|
Descriptor* subdesc = ruby_to_Descriptor(descriptor);
|
818
852
|
|
819
853
|
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
|
@@ -935,7 +969,8 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
|
|
935
969
|
VALUE value = Map_iter_value(&it);
|
936
970
|
|
937
971
|
upb_sink entry_sink;
|
938
|
-
upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
|
972
|
+
upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
|
973
|
+
&entry_sink);
|
939
974
|
upb_sink_startmsg(&entry_sink);
|
940
975
|
|
941
976
|
put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink);
|
@@ -956,7 +991,7 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
|
956
991
|
|
957
992
|
// Protect against cycles (possible because users may freely reassign message
|
958
993
|
// and repeated fields) by imposing a maximum recursion depth.
|
959
|
-
if (depth >
|
994
|
+
if (depth > ENCODE_MAX_NESTING) {
|
960
995
|
rb_raise(rb_eRuntimeError,
|
961
996
|
"Maximum recursion depth exceeded during encoding.");
|
962
997
|
}
|
@@ -1065,7 +1100,7 @@ static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) {
|
|
1065
1100
|
* wire format.
|
1066
1101
|
*/
|
1067
1102
|
VALUE Message_encode(VALUE klass, VALUE msg_rb) {
|
1068
|
-
VALUE descriptor =
|
1103
|
+
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
1069
1104
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
1070
1105
|
|
1071
1106
|
stringsink sink;
|
@@ -1074,15 +1109,16 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
|
|
1074
1109
|
const upb_handlers* serialize_handlers =
|
1075
1110
|
msgdef_pb_serialize_handlers(desc);
|
1076
1111
|
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1112
|
+
stackenv se;
|
1113
|
+
stackenv_init(&se, "Error occurred during encoding: %s");
|
1114
|
+
upb_pb_encoder* encoder =
|
1115
|
+
upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
|
1080
1116
|
|
1081
|
-
putmsg(msg_rb, desc, upb_pb_encoder_input(
|
1117
|
+
putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0);
|
1082
1118
|
|
1083
1119
|
VALUE ret = rb_str_new(sink.ptr, sink.len);
|
1084
1120
|
|
1085
|
-
|
1121
|
+
stackenv_uninit(&se);
|
1086
1122
|
stringsink_uninit(&sink);
|
1087
1123
|
|
1088
1124
|
return ret;
|
@@ -1095,7 +1131,7 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
|
|
1095
1131
|
* Encodes the given message object into its serialized JSON representation.
|
1096
1132
|
*/
|
1097
1133
|
VALUE Message_encode_json(VALUE klass, VALUE msg_rb) {
|
1098
|
-
VALUE descriptor =
|
1134
|
+
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
1099
1135
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
1100
1136
|
|
1101
1137
|
stringsink sink;
|
@@ -1104,64 +1140,18 @@ VALUE Message_encode_json(VALUE klass, VALUE msg_rb) {
|
|
1104
1140
|
const upb_handlers* serialize_handlers =
|
1105
1141
|
msgdef_json_serialize_handlers(desc);
|
1106
1142
|
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1143
|
+
stackenv se;
|
1144
|
+
stackenv_init(&se, "Error occurred during encoding: %s");
|
1145
|
+
upb_json_printer* printer =
|
1146
|
+
upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
|
1110
1147
|
|
1111
|
-
putmsg(msg_rb, desc, upb_json_printer_input(
|
1148
|
+
putmsg(msg_rb, desc, upb_json_printer_input(printer), 0);
|
1112
1149
|
|
1113
1150
|
VALUE ret = rb_str_new(sink.ptr, sink.len);
|
1114
1151
|
|
1115
|
-
|
1152
|
+
stackenv_uninit(&se);
|
1116
1153
|
stringsink_uninit(&sink);
|
1117
1154
|
|
1118
1155
|
return ret;
|
1119
1156
|
}
|
1120
1157
|
|
1121
|
-
/*
|
1122
|
-
* call-seq:
|
1123
|
-
* Google::Protobuf.encode(msg) => bytes
|
1124
|
-
*
|
1125
|
-
* Encodes the given message object to protocol buffers wire format. This is an
|
1126
|
-
* alternative to the #encode method on msg's class.
|
1127
|
-
*/
|
1128
|
-
VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb) {
|
1129
|
-
VALUE klass = CLASS_OF(msg_rb);
|
1130
|
-
return Message_encode(klass, msg_rb);
|
1131
|
-
}
|
1132
|
-
|
1133
|
-
/*
|
1134
|
-
* call-seq:
|
1135
|
-
* Google::Protobuf.encode_json(msg) => json_string
|
1136
|
-
*
|
1137
|
-
* Encodes the given message object to its JSON representation. This is an
|
1138
|
-
* alternative to the #encode_json method on msg's class.
|
1139
|
-
*/
|
1140
|
-
VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb) {
|
1141
|
-
VALUE klass = CLASS_OF(msg_rb);
|
1142
|
-
return Message_encode_json(klass, msg_rb);
|
1143
|
-
}
|
1144
|
-
|
1145
|
-
/*
|
1146
|
-
* call-seq:
|
1147
|
-
* Google::Protobuf.decode(class, bytes) => msg
|
1148
|
-
*
|
1149
|
-
* Decodes the given bytes as protocol buffers wire format under the
|
1150
|
-
* interpretation given by the given class's message definition. This is an
|
1151
|
-
* alternative to the #decode method on the given class.
|
1152
|
-
*/
|
1153
|
-
VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb) {
|
1154
|
-
return Message_decode(klass, msg_rb);
|
1155
|
-
}
|
1156
|
-
|
1157
|
-
/*
|
1158
|
-
* call-seq:
|
1159
|
-
* Google::Protobuf.decode_json(class, json_string) => msg
|
1160
|
-
*
|
1161
|
-
* Decodes the given JSON string under the interpretation given by the given
|
1162
|
-
* class's message definition. This is an alternative to the #decode_json method
|
1163
|
-
* on the given class.
|
1164
|
-
*/
|
1165
|
-
VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb) {
|
1166
|
-
return Message_decode_json(klass, msg_rb);
|
1167
|
-
}
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'mkmf'
|
4
4
|
|
5
|
-
$CFLAGS += " -O3 -std=c99 -Wno-unused-function
|
5
|
+
$CFLAGS += " -O3 -std=c99 -Wno-unused-function " +
|
6
|
+
"-Wno-declaration-after-statement -Wno-unused-variable " +
|
7
|
+
"-Wno-sign-compare -DNDEBUG "
|
6
8
|
|
7
9
|
$objs = ["protobuf.o", "defs.o", "storage.o", "message.o",
|
8
10
|
"repeated_field.o", "map.o", "encode_decode.o", "upb.o"]
|
@@ -53,7 +53,7 @@ rb_data_type_t Message_type = {
|
|
53
53
|
};
|
54
54
|
|
55
55
|
VALUE Message_alloc(VALUE klass) {
|
56
|
-
VALUE descriptor =
|
56
|
+
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
57
57
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
58
58
|
MessageHeader* msg = (MessageHeader*)ALLOC_N(
|
59
59
|
uint8_t, sizeof(MessageHeader) + desc->layout->size);
|
@@ -63,7 +63,7 @@ VALUE Message_alloc(VALUE klass) {
|
|
63
63
|
// a collection happens during object creation in layout_init().
|
64
64
|
VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
|
65
65
|
msg->descriptor = desc;
|
66
|
-
|
66
|
+
rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
|
67
67
|
|
68
68
|
layout_init(desc->layout, Message_data(msg));
|
69
69
|
|
@@ -86,7 +86,7 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
|
86
86
|
size_t case_ofs =
|
87
87
|
self->descriptor->layout->
|
88
88
|
fields[upb_fielddef_index(first_field)].case_offset;
|
89
|
-
uint32_t oneof_case = *((uint32_t*)(Message_data(self) + case_ofs));
|
89
|
+
uint32_t oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
|
90
90
|
|
91
91
|
if (oneof_case == ONEOF_CASE_NONE) {
|
92
92
|
return Qnil;
|
@@ -329,6 +329,31 @@ VALUE Message_inspect(VALUE _self) {
|
|
329
329
|
return str;
|
330
330
|
}
|
331
331
|
|
332
|
+
|
333
|
+
VALUE Message_to_h(VALUE _self) {
|
334
|
+
MessageHeader* self;
|
335
|
+
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
|
336
|
+
|
337
|
+
VALUE hash = rb_hash_new();
|
338
|
+
|
339
|
+
upb_msg_field_iter it;
|
340
|
+
for (upb_msg_field_begin(&it, self->descriptor->msgdef);
|
341
|
+
!upb_msg_field_done(&it);
|
342
|
+
upb_msg_field_next(&it)) {
|
343
|
+
const upb_fielddef* field = upb_msg_iter_field(&it);
|
344
|
+
VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
|
345
|
+
field);
|
346
|
+
VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
|
347
|
+
if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
348
|
+
msg_value = RepeatedField_to_ary(msg_value);
|
349
|
+
}
|
350
|
+
rb_hash_aset(hash, msg_key, msg_value);
|
351
|
+
}
|
352
|
+
return hash;
|
353
|
+
}
|
354
|
+
|
355
|
+
|
356
|
+
|
332
357
|
/*
|
333
358
|
* call-seq:
|
334
359
|
* Message.[](index) => value
|
@@ -376,7 +401,7 @@ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
|
|
376
401
|
* message class's type.
|
377
402
|
*/
|
378
403
|
VALUE Message_descriptor(VALUE klass) {
|
379
|
-
return
|
404
|
+
return rb_ivar_get(klass, descriptor_instancevar_interned);
|
380
405
|
}
|
381
406
|
|
382
407
|
VALUE build_class_from_descriptor(Descriptor* desc) {
|
@@ -397,8 +422,14 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
397
422
|
// their own toplevel constant class name.
|
398
423
|
rb_intern("Message"),
|
399
424
|
rb_cObject);
|
400
|
-
|
425
|
+
rb_ivar_set(klass, descriptor_instancevar_interned,
|
426
|
+
get_def_obj(desc->msgdef));
|
401
427
|
rb_define_alloc_func(klass, Message_alloc);
|
428
|
+
rb_require("google/protobuf/message_exts");
|
429
|
+
rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
|
430
|
+
rb_extend_object(
|
431
|
+
klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
|
432
|
+
|
402
433
|
rb_define_method(klass, "method_missing",
|
403
434
|
Message_method_missing, -1);
|
404
435
|
rb_define_method(klass, "initialize", Message_initialize, -1);
|
@@ -407,6 +438,8 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
407
438
|
rb_define_method(klass, "clone", Message_dup, 0);
|
408
439
|
rb_define_method(klass, "==", Message_eq, 1);
|
409
440
|
rb_define_method(klass, "hash", Message_hash, 0);
|
441
|
+
rb_define_method(klass, "to_h", Message_to_h, 0);
|
442
|
+
rb_define_method(klass, "to_hash", Message_to_h, 0);
|
410
443
|
rb_define_method(klass, "inspect", Message_inspect, 0);
|
411
444
|
rb_define_method(klass, "[]", Message_index, 1);
|
412
445
|
rb_define_method(klass, "[]=", Message_index_set, 2);
|
@@ -415,6 +448,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
415
448
|
rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
|
416
449
|
rb_define_singleton_method(klass, "encode_json", Message_encode_json, 1);
|
417
450
|
rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
|
451
|
+
|
418
452
|
return klass;
|
419
453
|
}
|
420
454
|
|
@@ -427,7 +461,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
427
461
|
*/
|
428
462
|
VALUE enum_lookup(VALUE self, VALUE number) {
|
429
463
|
int32_t num = NUM2INT(number);
|
430
|
-
VALUE desc =
|
464
|
+
VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
|
431
465
|
EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
|
432
466
|
|
433
467
|
const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
|
@@ -447,7 +481,7 @@ VALUE enum_lookup(VALUE self, VALUE number) {
|
|
447
481
|
*/
|
448
482
|
VALUE enum_resolve(VALUE self, VALUE sym) {
|
449
483
|
const char* name = rb_id2name(SYM2ID(sym));
|
450
|
-
VALUE desc =
|
484
|
+
VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
|
451
485
|
EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
|
452
486
|
|
453
487
|
int32_t num = 0;
|
@@ -467,7 +501,7 @@ VALUE enum_resolve(VALUE self, VALUE sym) {
|
|
467
501
|
* EnumDescriptor corresponding to this enum type.
|
468
502
|
*/
|
469
503
|
VALUE enum_descriptor(VALUE self) {
|
470
|
-
return
|
504
|
+
return rb_ivar_get(self, descriptor_instancevar_interned);
|
471
505
|
}
|
472
506
|
|
473
507
|
VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
|
@@ -492,7 +526,8 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
|
|
492
526
|
rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
|
493
527
|
rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
|
494
528
|
rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
|
495
|
-
|
529
|
+
rb_ivar_set(mod, descriptor_instancevar_interned,
|
530
|
+
get_def_obj(enumdesc->enumdef));
|
496
531
|
|
497
532
|
return mod;
|
498
533
|
}
|
@@ -64,6 +64,15 @@ rb_encoding* kRubyStringUtf8Encoding;
|
|
64
64
|
rb_encoding* kRubyStringASCIIEncoding;
|
65
65
|
rb_encoding* kRubyString8bitEncoding;
|
66
66
|
|
67
|
+
// Ruby-interned string: "descriptor". We use this identifier to store an
|
68
|
+
// instance variable on message classes we create in order to link them back to
|
69
|
+
// their descriptors.
|
70
|
+
//
|
71
|
+
// We intern this once at module load time then use the interned identifier at
|
72
|
+
// runtime in order to avoid the cost of repeatedly interning in hot paths.
|
73
|
+
const char* kDescriptorInstanceVar = "descriptor";
|
74
|
+
ID descriptor_instancevar_interned;
|
75
|
+
|
67
76
|
// -----------------------------------------------------------------------------
|
68
77
|
// Initialization/entry point.
|
69
78
|
// -----------------------------------------------------------------------------
|
@@ -71,6 +80,7 @@ rb_encoding* kRubyString8bitEncoding;
|
|
71
80
|
// This must be named "Init_protobuf_c" because the Ruby module is named
|
72
81
|
// "protobuf_c" -- the VM looks for this symbol in our .so.
|
73
82
|
void Init_protobuf_c() {
|
83
|
+
descriptor_instancevar_interned = rb_intern(kDescriptorInstanceVar);
|
74
84
|
VALUE google = rb_define_module("Google");
|
75
85
|
VALUE protobuf = rb_define_module_under(google, "Protobuf");
|
76
86
|
VALUE internal = rb_define_module_under(protobuf, "Internal");
|
@@ -86,13 +96,6 @@ void Init_protobuf_c() {
|
|
86
96
|
RepeatedField_register(protobuf);
|
87
97
|
Map_register(protobuf);
|
88
98
|
|
89
|
-
rb_define_singleton_method(protobuf, "encode", Google_Protobuf_encode, 1);
|
90
|
-
rb_define_singleton_method(protobuf, "decode", Google_Protobuf_decode, 2);
|
91
|
-
rb_define_singleton_method(protobuf, "encode_json",
|
92
|
-
Google_Protobuf_encode_json, 1);
|
93
|
-
rb_define_singleton_method(protobuf, "decode_json",
|
94
|
-
Google_Protobuf_decode_json, 2);
|
95
|
-
|
96
99
|
rb_define_singleton_method(protobuf, "deep_copy",
|
97
100
|
Google_Protobuf_deep_copy, 1);
|
98
101
|
|