aboutsummaryrefslogtreecommitdiffhomepage
path: root/ruby/ext/google
diff options
context:
space:
mode:
Diffstat (limited to 'ruby/ext/google')
-rw-r--r--ruby/ext/google/protobuf_c/defs.c32
-rw-r--r--ruby/ext/google/protobuf_c/encode_decode.c88
-rw-r--r--ruby/ext/google/protobuf_c/extconf.rb4
-rw-r--r--ruby/ext/google/protobuf_c/map.c2
-rw-r--r--ruby/ext/google/protobuf_c/message.c10
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.c4
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.h2
-rw-r--r--ruby/ext/google/protobuf_c/repeated_field.c2
-rw-r--r--ruby/ext/google/protobuf_c/storage.c46
9 files changed, 149 insertions, 41 deletions
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index 34d9663a..9fe04503 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -76,7 +76,7 @@ static upb_enumdef* check_enum_notfrozen(const upb_enumdef* def) {
// -----------------------------------------------------------------------------
#define DEFINE_CLASS(name, string_name) \
- VALUE c ## name; \
+ VALUE c ## name = Qnil; \
const rb_data_type_t _ ## name ## _type = { \
string_name, \
{ name ## _mark, name ## _free, NULL }, \
@@ -126,11 +126,11 @@ void DescriptorPool_register(VALUE module) {
rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
rb_define_singleton_method(klass, "generated_pool",
DescriptorPool_generated_pool, 0);
- cDescriptorPool = klass;
rb_gc_register_address(&cDescriptorPool);
+ cDescriptorPool = klass;
- generated_pool = rb_class_new_instance(0, NULL, klass);
rb_gc_register_address(&generated_pool);
+ generated_pool = rb_class_new_instance(0, NULL, klass);
}
static void add_descriptor_to_pool(DescriptorPool* self,
@@ -299,8 +299,8 @@ void Descriptor_register(VALUE module) {
rb_define_method(klass, "name", Descriptor_name, 0);
rb_define_method(klass, "name=", Descriptor_name_set, 1);
rb_include_module(klass, rb_mEnumerable);
- cDescriptor = klass;
rb_gc_register_address(&cDescriptor);
+ cDescriptor = klass;
}
/*
@@ -518,8 +518,8 @@ void FieldDescriptor_register(VALUE module) {
rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
rb_define_method(klass, "get", FieldDescriptor_get, 1);
rb_define_method(klass, "set", FieldDescriptor_set, 2);
- cFieldDescriptor = klass;
rb_gc_register_address(&cFieldDescriptor);
+ cFieldDescriptor = klass;
}
/*
@@ -812,7 +812,7 @@ VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value) {
upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
const char* str = get_str(value);
if (!upb_fielddef_hassubdef(self->fielddef)) {
- rb_raise(rb_eTypeError, "FieldDescriptor does not have subdef.");
+ rb_raise(cTypeError, "FieldDescriptor does not have subdef.");
}
CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status),
"Error setting submessage name");
@@ -854,7 +854,7 @@ VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
MessageHeader* msg;
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
- rb_raise(rb_eTypeError, "get method called on wrong message type");
+ rb_raise(cTypeError, "get method called on wrong message type");
}
return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
}
@@ -872,7 +872,7 @@ VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
MessageHeader* msg;
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
- rb_raise(rb_eTypeError, "set method called on wrong message type");
+ rb_raise(cTypeError, "set method called on wrong message type");
}
layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value);
return Qnil;
@@ -916,8 +916,8 @@ void OneofDescriptor_register(VALUE module) {
rb_define_method(klass, "add_field", OneofDescriptor_add_field, 1);
rb_define_method(klass, "each", OneofDescriptor_each, 0);
rb_include_module(klass, rb_mEnumerable);
- cOneofDescriptor = klass;
rb_gc_register_address(&cOneofDescriptor);
+ cOneofDescriptor = klass;
}
/*
@@ -1037,8 +1037,8 @@ void EnumDescriptor_register(VALUE module) {
rb_define_method(klass, "each", EnumDescriptor_each, 0);
rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
rb_include_module(klass, rb_mEnumerable);
- cEnumDescriptor = klass;
rb_gc_register_address(&cEnumDescriptor);
+ cEnumDescriptor = klass;
}
/*
@@ -1202,8 +1202,8 @@ void MessageBuilderContext_register(VALUE module) {
rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
rb_define_method(klass, "map", MessageBuilderContext_map, -1);
rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
- cMessageBuilderContext = klass;
rb_gc_register_address(&cMessageBuilderContext);
+ cMessageBuilderContext = klass;
}
/*
@@ -1491,8 +1491,8 @@ void OneofBuilderContext_register(VALUE module) {
rb_define_method(klass, "initialize",
OneofBuilderContext_initialize, 2);
rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
- cOneofBuilderContext = klass;
rb_gc_register_address(&cOneofBuilderContext);
+ cOneofBuilderContext = klass;
}
/*
@@ -1569,8 +1569,8 @@ void EnumBuilderContext_register(VALUE module) {
rb_define_method(klass, "initialize",
EnumBuilderContext_initialize, 1);
rb_define_method(klass, "value", EnumBuilderContext_value, 2);
- cEnumBuilderContext = klass;
rb_gc_register_address(&cEnumBuilderContext);
+ cEnumBuilderContext = klass;
}
/*
@@ -1645,8 +1645,8 @@ void Builder_register(VALUE module) {
rb_define_method(klass, "add_enum", Builder_add_enum, 1);
rb_define_method(klass, "initialize", Builder_initialize, 0);
rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1);
- cBuilder = klass;
rb_gc_register_address(&cBuilder);
+ cBuilder = klass;
}
/*
@@ -1713,7 +1713,7 @@ static void validate_msgdef(const upb_msgdef* msgdef) {
upb_msg_field_next(&it)) {
const upb_fielddef* field = upb_msg_iter_field(&it);
if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
- rb_raise(rb_eTypeError, "Required fields are unsupported in proto3.");
+ rb_raise(cTypeError, "Required fields are unsupported in proto3.");
}
}
}
@@ -1723,7 +1723,7 @@ static void validate_enumdef(const upb_enumdef* enumdef) {
// value.)
const char* lookup = upb_enumdef_iton(enumdef, 0);
if (lookup == NULL) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Enum definition does not contain a value for '0'.");
}
}
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
index d1b6e89e..12080d03 100644
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -1305,3 +1305,91 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
}
}
+static void discard_unknown(VALUE msg_rb, const Descriptor* desc) {
+ MessageHeader* msg;
+ upb_msg_field_iter it;
+
+ TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+ stringsink* unknown = msg->unknown_fields;
+ if (unknown != NULL) {
+ stringsink_uninit(unknown);
+ msg->unknown_fields = NULL;
+ }
+
+ for (upb_msg_field_begin(&it, desc->msgdef);
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ upb_fielddef *f = upb_msg_iter_field(&it);
+ uint32_t offset =
+ desc->layout->fields[upb_fielddef_index(f)].offset +
+ sizeof(MessageHeader);
+
+ if (upb_fielddef_containingoneof(f)) {
+ uint32_t oneof_case_offset =
+ desc->layout->fields[upb_fielddef_index(f)].case_offset +
+ sizeof(MessageHeader);
+ // For a oneof, check that this field is actually present -- skip all the
+ // below if not.
+ if (DEREF(msg, oneof_case_offset, uint32_t) !=
+ upb_fielddef_number(f)) {
+ continue;
+ }
+ // Otherwise, fall through to the appropriate singular-field handler
+ // below.
+ }
+
+ if (!upb_fielddef_issubmsg(f)) {
+ continue;
+ }
+
+ if (is_map_field(f)) {
+ if (!upb_fielddef_issubmsg(map_field_value(f))) continue;
+ VALUE map = DEREF(msg, offset, VALUE);
+ if (map == Qnil) continue;
+ Map_iter map_it;
+ for (Map_begin(map, &map_it); !Map_done(&map_it); Map_next(&map_it)) {
+ VALUE submsg = Map_iter_value(&map_it);
+ VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
+ const Descriptor* subdesc = ruby_to_Descriptor(descriptor);
+ discard_unknown(submsg, subdesc);
+ }
+ } else if (upb_fielddef_isseq(f)) {
+ VALUE ary = DEREF(msg, offset, VALUE);
+ if (ary == Qnil) continue;
+ int size = NUM2INT(RepeatedField_length(ary));
+ for (int i = 0; i < size; i++) {
+ void* memory = RepeatedField_index_native(ary, i);
+ VALUE submsg = *((VALUE *)memory);
+ VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
+ const Descriptor* subdesc = ruby_to_Descriptor(descriptor);
+ discard_unknown(submsg, subdesc);
+ }
+ } else {
+ VALUE submsg = DEREF(msg, offset, VALUE);
+ if (submsg == Qnil) continue;
+ VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
+ const Descriptor* subdesc = ruby_to_Descriptor(descriptor);
+ discard_unknown(submsg, subdesc);
+ }
+ }
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.discard_unknown(msg)
+ *
+ * Discard unknown fields in the given message object and recursively discard
+ * unknown fields in submessages.
+ */
+VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) {
+ VALUE klass = CLASS_OF(msg_rb);
+ VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
+ if (klass == cRepeatedField || klass == cMap) {
+ rb_raise(rb_eArgError, "Expected proto msg for discard unknown.");
+ } else {
+ discard_unknown(msg_rb, desc);
+ }
+ return Qnil;
+}
diff --git a/ruby/ext/google/protobuf_c/extconf.rb b/ruby/ext/google/protobuf_c/extconf.rb
index 0886e607..cc097e11 100644
--- a/ruby/ext/google/protobuf_c/extconf.rb
+++ b/ruby/ext/google/protobuf_c/extconf.rb
@@ -2,7 +2,9 @@
require 'mkmf'
-$CFLAGS += " -std=c99 -O3 -DNDEBUG"
+unless RUBY_PLATFORM =~ /mswin|mingw/
+ $CFLAGS += " -std=c99 -O3 -DNDEBUG"
+end
if RUBY_PLATFORM =~ /linux/
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
index 26e22dc7..8c2f6424 100644
--- a/ruby/ext/google/protobuf_c/map.c
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -825,8 +825,8 @@ VALUE Map_iter_value(Map_iter* iter) {
void Map_register(VALUE module) {
VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
rb_define_alloc_func(klass, Map_alloc);
- cMap = klass;
rb_gc_register_address(&cMap);
+ cMap = klass;
rb_define_method(klass, "initialize", Map_init, -1);
rb_define_method(klass, "each", Map_each, 0);
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index bc73d48c..721c1112 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -256,6 +256,10 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
"Unknown field name '%s' in initialization map entry.", name);
}
+ if (TYPE(val) == T_NIL) {
+ return 0;
+ }
+
if (is_map_field(f)) {
VALUE map;
@@ -540,9 +544,9 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
get_def_obj(desc->msgdef));
rb_define_alloc_func(klass, Message_alloc);
rb_require("google/protobuf/message_exts");
- rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
+ rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
rb_extend_object(
- klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
+ klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
rb_define_method(klass, "method_missing",
Message_method_missing, -1);
@@ -631,7 +635,7 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
const char* name = upb_enum_iter_name(&it);
int32_t value = upb_enum_iter_number(&it);
if (name[0] < 'A' || name[0] > 'Z') {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Enum value '%s' does not start with an uppercase letter "
"as is required for Ruby constants.",
name);
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index c7750c44..fe6bb406 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -41,6 +41,7 @@ VALUE upb_def_to_ruby_obj_map;
VALUE cError;
VALUE cParseError;
+VALUE cTypeError;
void add_def_obj(const void* def, VALUE value) {
rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value);
@@ -102,7 +103,10 @@ void Init_protobuf_c() {
cError = rb_const_get(protobuf, rb_intern("Error"));
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
+ cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
+ rb_define_singleton_method(protobuf, "discard_unknown",
+ Google_Protobuf_discard_unknown, 1);
rb_define_singleton_method(protobuf, "deep_copy",
Google_Protobuf_deep_copy, 1);
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index 1291ac59..3e5c0520 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -161,6 +161,7 @@ extern VALUE cBuilder;
extern VALUE cError;
extern VALUE cParseError;
+extern VALUE cTypeError;
// We forward-declare all of the Ruby method implementations here because we
// sometimes call the methods directly across .c files, rather than going
@@ -515,6 +516,7 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb);
VALUE Message_decode_json(VALUE klass, VALUE data);
VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass);
+VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb);
VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
VALUE build_module_from_enumdesc(EnumDescriptor* enumdef);
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
index 1c651c19..c6620ee6 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.c
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -626,8 +626,8 @@ void RepeatedField_register(VALUE module) {
VALUE klass = rb_define_class_under(
module, "RepeatedField", rb_cObject);
rb_define_alloc_func(klass, RepeatedField_alloc);
- cRepeatedField = klass;
rb_gc_register_address(&cRepeatedField);
+ cRepeatedField = klass;
rb_define_method(klass, "initialize",
RepeatedField_init, -1);
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
index 24064dfd..5d0ac976 100644
--- a/ruby/ext/google/protobuf_c/storage.c
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -96,7 +96,7 @@ static bool is_ruby_num(VALUE value) {
void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
if (!is_ruby_num(val)) {
- rb_raise(rb_eTypeError, "Expected number type for integral field.");
+ rb_raise(cTypeError, "Expected number type for integral field.");
}
// NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
@@ -153,13 +153,13 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
switch (type) {
case UPB_TYPE_FLOAT:
if (!is_ruby_num(value)) {
- rb_raise(rb_eTypeError, "Expected number type for float field.");
+ rb_raise(cTypeError, "Expected number type for float field.");
}
DEREF(memory, float) = NUM2DBL(value);
break;
case UPB_TYPE_DOUBLE:
if (!is_ruby_num(value)) {
- rb_raise(rb_eTypeError, "Expected number type for double field.");
+ rb_raise(cTypeError, "Expected number type for double field.");
}
DEREF(memory, double) = NUM2DBL(value);
break;
@@ -170,7 +170,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
} else if (value == Qfalse) {
val = 0;
} else {
- rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
+ rb_raise(cTypeError, "Invalid argument for boolean field.");
}
DEREF(memory, int8_t) = val;
break;
@@ -179,7 +179,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
if (CLASS_OF(value) == rb_cSymbol) {
value = rb_funcall(value, rb_intern("to_s"), 0, NULL);
} else if (CLASS_OF(value) != rb_cString) {
- rb_raise(rb_eTypeError, "Invalid argument for string field.");
+ rb_raise(cTypeError, "Invalid argument for string field.");
}
DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
@@ -187,7 +187,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
case UPB_TYPE_BYTES: {
if (CLASS_OF(value) != rb_cString) {
- rb_raise(rb_eTypeError, "Invalid argument for string field.");
+ rb_raise(cTypeError, "Invalid argument for string field.");
}
DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
@@ -197,7 +197,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
if (CLASS_OF(value) == CLASS_OF(Qnil)) {
value = Qnil;
} else if (CLASS_OF(value) != type_class) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Invalid type %s to assign to submessage field.",
rb_class2name(CLASS_OF(value)));
}
@@ -209,7 +209,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
if (TYPE(value) == T_STRING) {
value = rb_funcall(value, rb_intern("to_sym"), 0, NULL);
} else if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Expected number or symbol type for enum field.");
}
if (TYPE(value) == T_SYMBOL) {
@@ -598,20 +598,28 @@ static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
- rb_raise(rb_eTypeError, "Expected repeated field array");
+ rb_raise(cTypeError, "Expected repeated field array");
}
self = ruby_to_RepeatedField(val);
if (self->field_type != upb_fielddef_type(field)) {
- rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
+ rb_raise(cTypeError, "Repeated field array has wrong element type");
}
- if (self->field_type == UPB_TYPE_MESSAGE ||
- self->field_type == UPB_TYPE_ENUM) {
+ if (self->field_type == UPB_TYPE_MESSAGE) {
if (self->field_type_class !=
- get_def_obj(upb_fielddef_subdef(field))) {
- rb_raise(rb_eTypeError,
- "Repeated field array has wrong message/enum class");
+ Descriptor_msgclass(get_def_obj(upb_fielddef_subdef(field)))) {
+ rb_raise(cTypeError,
+ "Repeated field array has wrong message class");
+ }
+ }
+
+
+ if (self->field_type == UPB_TYPE_ENUM) {
+ if (self->field_type_class !=
+ EnumDescriptor_enummodule(get_def_obj(upb_fielddef_subdef(field)))) {
+ rb_raise(cTypeError,
+ "Repeated field array has wrong enum class");
}
}
}
@@ -623,21 +631,21 @@ static void check_map_field_type(VALUE val, const upb_fielddef* field) {
if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
RTYPEDDATA_TYPE(val) != &Map_type) {
- rb_raise(rb_eTypeError, "Expected Map instance");
+ rb_raise(cTypeError, "Expected Map instance");
}
self = ruby_to_Map(val);
if (self->key_type != upb_fielddef_type(key_field)) {
- rb_raise(rb_eTypeError, "Map key type does not match field's key type");
+ rb_raise(cTypeError, "Map key type does not match field's key type");
}
if (self->value_type != upb_fielddef_type(value_field)) {
- rb_raise(rb_eTypeError, "Map value type does not match field's value type");
+ rb_raise(cTypeError, "Map value type does not match field's value type");
}
if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
if (self->value_type_class !=
get_def_obj(upb_fielddef_subdef(value_field))) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Map value type has wrong message/enum class");
}
}