google-protobuf 3.0.0.alpha.2.0 → 3.0.0.alpha.3
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.
- 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
|
|