Merge pull request #10281 from casperisfine/ruby-smaller-message-classes
Ruby: Use class inheritance to save memory
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index e430b79..b118785 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -37,6 +37,7 @@
#include "repeated_field.h"
static VALUE cParseError = Qnil;
+static VALUE cAbstractMessage = Qnil;
static ID descriptor_instancevar_interned;
static VALUE initialize_rb_class_with_no_args(VALUE klass) {
@@ -1201,36 +1202,8 @@
klass = rb_define_class_id(
// Docs say this parameter is ignored. User will assign return value to
// their own toplevel constant class name.
- rb_intern("Message"), rb_cObject);
+ rb_intern("Message"), cAbstractMessage);
rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
- rb_define_alloc_func(klass, Message_alloc);
- rb_require("google/protobuf/message_exts");
- rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
- rb_extend_object(
- klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
-
- rb_define_method(klass, "method_missing", Message_method_missing, -1);
- rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
- -1);
- rb_define_method(klass, "initialize", Message_initialize, -1);
- rb_define_method(klass, "dup", Message_dup, 0);
- // Also define #clone so that we don't inherit Object#clone.
- rb_define_method(klass, "clone", Message_dup, 0);
- rb_define_method(klass, "==", Message_eq, 1);
- rb_define_method(klass, "eql?", Message_eq, 1);
- rb_define_method(klass, "freeze", Message_freeze, 0);
- rb_define_method(klass, "hash", Message_hash, 0);
- rb_define_method(klass, "to_h", Message_to_h, 0);
- rb_define_method(klass, "inspect", Message_inspect, 0);
- rb_define_method(klass, "to_s", Message_inspect, 0);
- rb_define_method(klass, "[]", Message_index, 1);
- rb_define_method(klass, "[]=", Message_index_set, 2);
- rb_define_singleton_method(klass, "decode", Message_decode, -1);
- rb_define_singleton_method(klass, "encode", Message_encode, -1);
- rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
- rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
- rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
-
return klass;
}
@@ -1392,8 +1365,38 @@
return self->msg;
}
+static void Message_define_class(VALUE klass) {
+ rb_define_alloc_func(klass, Message_alloc);
+
+ rb_require("google/protobuf/message_exts");
+ rb_define_method(klass, "method_missing", Message_method_missing, -1);
+ rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
+ -1);
+ rb_define_method(klass, "initialize", Message_initialize, -1);
+ rb_define_method(klass, "dup", Message_dup, 0);
+ // Also define #clone so that we don't inherit Object#clone.
+ rb_define_method(klass, "clone", Message_dup, 0);
+ rb_define_method(klass, "==", Message_eq, 1);
+ rb_define_method(klass, "eql?", Message_eq, 1);
+ rb_define_method(klass, "freeze", Message_freeze, 0);
+ rb_define_method(klass, "hash", Message_hash, 0);
+ rb_define_method(klass, "to_h", Message_to_h, 0);
+ rb_define_method(klass, "inspect", Message_inspect, 0);
+ rb_define_method(klass, "to_s", Message_inspect, 0);
+ rb_define_method(klass, "[]", Message_index, 1);
+ rb_define_method(klass, "[]=", Message_index_set, 2);
+ rb_define_singleton_method(klass, "decode", Message_decode, -1);
+ rb_define_singleton_method(klass, "encode", Message_encode, -1);
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
+}
+
void Message_register(VALUE protobuf) {
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
+ cAbstractMessage = rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
+ Message_define_class(cAbstractMessage);
+ rb_gc_register_address(&cAbstractMessage);
// Ruby-interned string: "descriptor". We use this identifier to store an
// instance variable on message classes we create in order to link them back
diff --git a/ruby/lib/google/protobuf/message_exts.rb b/ruby/lib/google/protobuf/message_exts.rb
index 6608521..3cc1a08 100644
--- a/ruby/lib/google/protobuf/message_exts.rb
+++ b/ruby/lib/google/protobuf/message_exts.rb
@@ -49,5 +49,10 @@
end
end
+ class AbstractMessage
+ include MessageExts
+ extend MessageExts::ClassMethods
+ end
+ private_constant :AbstractMessage
end
end