diff options
author | Chris Fallin <cfallin@c1f.net> | 2014-12-12 15:58:26 -0800 |
---|---|---|
committer | Chris Fallin <cfallin@c1f.net> | 2014-12-12 15:58:26 -0800 |
commit | 91473dcebfbd90a8e256568e287e168b70c77ff0 (patch) | |
tree | 6a2fc1a9242659963b5f3bae9c146d957027f5e2 /ruby/ext/protobuf_c | |
parent | f473bb9903370cc9324b0881873e0d0861f5d325 (diff) | |
download | protobuf-91473dcebfbd90a8e256568e287e168b70c77ff0.tar.gz protobuf-91473dcebfbd90a8e256568e287e168b70c77ff0.tar.bz2 protobuf-91473dcebfbd90a8e256568e287e168b70c77ff0.zip |
Rename protobuf Ruby module to google/protobuf and rework its build
system. The Ruby module build now uses an amalgamated distribution of
upb, and successfully builds a Ruby gem called 'google-protobuf' with
module 'google/protobuf'.
Diffstat (limited to 'ruby/ext/protobuf_c')
-rw-r--r-- | ruby/ext/protobuf_c/defs.c | 1286 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/encode_decode.c | 755 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/extconf.rb | 23 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/message.c | 463 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/protobuf.c | 102 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/protobuf.h | 404 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/repeated_field.c | 597 | ||||
-rw-r--r-- | ruby/ext/protobuf_c/storage.c | 577 |
8 files changed, 0 insertions, 4207 deletions
diff --git a/ruby/ext/protobuf_c/defs.c b/ruby/ext/protobuf_c/defs.c deleted file mode 100644 index bb6f10e1..00000000 --- a/ruby/ext/protobuf_c/defs.c +++ /dev/null @@ -1,1286 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Common utilities. -// ----------------------------------------------------------------------------- - -const char* kDescriptorInstanceVar = "descriptor"; - -static const char* get_str(VALUE str) { - Check_Type(str, T_STRING); - return RSTRING_PTR(str); -} - -static VALUE rb_str_maybe_null(const char* s) { - if (s == NULL) { - s = ""; - } - return rb_str_new2(s); -} - -static upb_def* check_notfrozen(const upb_def* def) { - if (upb_def_isfrozen(def)) { - rb_raise(rb_eRuntimeError, - "Attempt to modify a frozen descriptor. Once descriptors are " - "added to the descriptor pool, they may not be modified."); - } - return (upb_def*)def; -} - -static upb_msgdef* check_msg_notfrozen(const upb_msgdef* def) { - return (upb_msgdef*)check_notfrozen((const upb_def*)def); -} - -static upb_fielddef* check_field_notfrozen(const upb_fielddef* def) { - return (upb_fielddef*)check_notfrozen((const upb_def*)def); -} - -static upb_enumdef* check_enum_notfrozen(const upb_enumdef* def) { - return (upb_enumdef*)check_notfrozen((const upb_def*)def); -} - -// ----------------------------------------------------------------------------- -// DescriptorPool. -// ----------------------------------------------------------------------------- - -#define DEFINE_CLASS(name, string_name) \ - VALUE c ## name; \ - const rb_data_type_t _ ## name ## _type = { \ - string_name, \ - { name ## _mark, name ## _free, NULL }, \ - }; \ - name* ruby_to_ ## name(VALUE val) { \ - name* ret; \ - TypedData_Get_Struct(val, name, &_ ## name ## _type, ret); \ - return ret; \ - } \ - -#define DEFINE_SELF(type, var, rb_var) \ - type* var = ruby_to_ ## type(rb_var); - -// Global singleton DescriptorPool. The user is free to create others, but this -// is used by generated code. -VALUE generated_pool; - -DEFINE_CLASS(DescriptorPool, "Google::Protobuf::DescriptorPool"); - -void DescriptorPool_mark(void* _self) { -} - -void DescriptorPool_free(void* _self) { - DescriptorPool* self = _self; - upb_symtab_unref(self->symtab, &self->symtab); - xfree(self); -} - -/* - * call-seq: - * DescriptorPool.new => pool - * - * Creates a new, empty, descriptor pool. - */ -VALUE DescriptorPool_alloc(VALUE klass) { - DescriptorPool* self = ALLOC(DescriptorPool); - self->symtab = upb_symtab_new(&self->symtab); - return TypedData_Wrap_Struct(klass, &_DescriptorPool_type, self); -} - -void DescriptorPool_register(VALUE module) { - VALUE klass = rb_define_class_under( - module, "DescriptorPool", rb_cObject); - rb_define_alloc_func(klass, DescriptorPool_alloc); - rb_define_method(klass, "add", DescriptorPool_add, 1); - rb_define_method(klass, "build", DescriptorPool_build, 0); - 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); - - generated_pool = rb_class_new_instance(0, NULL, klass); - rb_gc_register_address(&generated_pool); -} - -static void add_descriptor_to_pool(DescriptorPool* self, - Descriptor* descriptor) { - CHECK_UPB( - upb_symtab_add(self->symtab, (upb_def**)&descriptor->msgdef, 1, - NULL, &status), - "Adding Descriptor to DescriptorPool failed"); -} - -static void add_enumdesc_to_pool(DescriptorPool* self, - EnumDescriptor* enumdesc) { - CHECK_UPB( - upb_symtab_add(self->symtab, (upb_def**)&enumdesc->enumdef, 1, - NULL, &status), - "Adding EnumDescriptor to DescriptorPool failed"); -} - -/* - * call-seq: - * DescriptorPool.add(descriptor) - * - * Adds the given Descriptor or EnumDescriptor to this pool. All references to - * other types in a Descriptor's fields must be resolvable within this pool or - * an exception will be raised. - */ -VALUE DescriptorPool_add(VALUE _self, VALUE def) { - DEFINE_SELF(DescriptorPool, self, _self); - VALUE def_klass = rb_obj_class(def); - if (def_klass == cDescriptor) { - add_descriptor_to_pool(self, ruby_to_Descriptor(def)); - } else if (def_klass == cEnumDescriptor) { - add_enumdesc_to_pool(self, ruby_to_EnumDescriptor(def)); - } else { - rb_raise(rb_eArgError, - "Second argument must be a Descriptor or EnumDescriptor."); - } - return Qnil; -} - -/* - * call-seq: - * DescriptorPool.build(&block) - * - * Invokes the block with a Builder instance as self. All message and enum types - * added within the block are committed to the pool atomically, and may refer - * (co)recursively to each other. The user should call Builder#add_message and - * Builder#add_enum within the block as appropriate. This is the recommended, - * idiomatic way to define new message and enum types. - */ -VALUE DescriptorPool_build(VALUE _self) { - VALUE ctx = rb_class_new_instance(0, NULL, cBuilder); - VALUE block = rb_block_proc(); - rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); - rb_funcall(ctx, rb_intern("finalize_to_pool"), 1, _self); - return Qnil; -} - -/* - * call-seq: - * DescriptorPool.lookup(name) => descriptor - * - * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none - * exists with the given name. - */ -VALUE DescriptorPool_lookup(VALUE _self, VALUE name) { - DEFINE_SELF(DescriptorPool, self, _self); - const char* name_str = get_str(name); - const upb_def* def = upb_symtab_lookup(self->symtab, name_str); - if (!def) { - return Qnil; - } - return get_def_obj(def); -} - -/* - * call-seq: - * DescriptorPool.generated_pool => descriptor_pool - * - * Class method that returns the global DescriptorPool. This is a singleton into - * which generated-code message and enum types are registered. The user may also - * register types in this pool for convenience so that they do not have to hold - * a reference to a private pool instance. - */ -VALUE DescriptorPool_generated_pool(VALUE _self) { - return generated_pool; -} - -// ----------------------------------------------------------------------------- -// Descriptor. -// ----------------------------------------------------------------------------- - -DEFINE_CLASS(Descriptor, "Google::Protobuf::Descriptor"); - -void Descriptor_mark(void* _self) { - Descriptor* self = _self; - rb_gc_mark(self->klass); -} - -void Descriptor_free(void* _self) { - Descriptor* self = _self; - upb_msgdef_unref(self->msgdef, &self->msgdef); - if (self->layout) { - free_layout(self->layout); - } - if (self->fill_handlers) { - upb_handlers_unref(self->fill_handlers, &self->fill_handlers); - } - if (self->fill_method) { - upb_pbdecodermethod_unref(self->fill_method, &self->fill_method); - } - if (self->pb_serialize_handlers) { - upb_handlers_unref(self->pb_serialize_handlers, - &self->pb_serialize_handlers); - } - if (self->json_serialize_handlers) { - upb_handlers_unref(self->pb_serialize_handlers, - &self->json_serialize_handlers); - } - xfree(self); -} - -/* - * call-seq: - * Descriptor.new => descriptor - * - * Creates a new, empty, message type descriptor. At a minimum, its name must be - * set before it is added to a pool. It cannot be used to create messages until - * it is added to a pool, after which it becomes immutable (as part of a - * finalization process). - */ -VALUE Descriptor_alloc(VALUE klass) { - Descriptor* self = ALLOC(Descriptor); - VALUE ret = TypedData_Wrap_Struct(klass, &_Descriptor_type, self); - self->msgdef = upb_msgdef_new(&self->msgdef); - self->klass = Qnil; - self->layout = NULL; - self->fill_handlers = NULL; - self->fill_method = NULL; - self->pb_serialize_handlers = NULL; - self->json_serialize_handlers = NULL; - return ret; -} - -void Descriptor_register(VALUE module) { - VALUE klass = rb_define_class_under( - module, "Descriptor", rb_cObject); - rb_define_alloc_func(klass, Descriptor_alloc); - rb_define_method(klass, "each", Descriptor_each, 0); - rb_define_method(klass, "lookup", Descriptor_lookup, 1); - rb_define_method(klass, "add_field", Descriptor_add_field, 1); - rb_define_method(klass, "msgclass", Descriptor_msgclass, 0); - 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); -} - -/* - * call-seq: - * Descriptor.name => name - * - * Returns the name of this message type as a fully-qualfied string (e.g., - * My.Package.MessageType). - */ -VALUE Descriptor_name(VALUE _self) { - DEFINE_SELF(Descriptor, self, _self); - return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef)); -} - -/* - * call-seq: - * Descriptor.name = name - * - * Assigns a name to this message type. The descriptor must not have been added - * to a pool yet. - */ -VALUE Descriptor_name_set(VALUE _self, VALUE str) { - DEFINE_SELF(Descriptor, self, _self); - upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef); - const char* name = get_str(str); - CHECK_UPB( - upb_msgdef_setfullname(mut_def, name, &status), - "Error setting Descriptor name"); - return Qnil; -} - -/* - * call-seq: - * Descriptor.each(&block) - * - * Iterates over fields in this message type, yielding to the block on each one. - */ -VALUE Descriptor_each(VALUE _self) { - DEFINE_SELF(Descriptor, self, _self); - - upb_msg_iter it; - for (upb_msg_begin(&it, self->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - VALUE obj = get_def_obj(field); - rb_yield(obj); - } - return Qnil; -} - -/* - * call-seq: - * Descriptor.lookup(name) => FieldDescriptor - * - * Returns the field descriptor for the field with the given name, if present, - * or nil if none. - */ -VALUE Descriptor_lookup(VALUE _self, VALUE name) { - DEFINE_SELF(Descriptor, self, _self); - const char* s = get_str(name); - const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s); - if (field == NULL) { - return Qnil; - } - return get_def_obj(field); -} - -/* - * call-seq: - * Descriptor.add_field(field) => nil - * - * Adds the given FieldDescriptor to this message type. The descriptor must not - * have been added to a pool yet. Raises an exception if a field with the same - * name or number already exists. Sub-type references (e.g. for fields of type - * message) are not resolved at this point. - */ -VALUE Descriptor_add_field(VALUE _self, VALUE obj) { - DEFINE_SELF(Descriptor, self, _self); - upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef); - FieldDescriptor* def = ruby_to_FieldDescriptor(obj); - upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef); - CHECK_UPB( - upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status), - "Adding field to Descriptor failed"); - add_def_obj(def->fielddef, obj); - return Qnil; -} - -/* - * call-seq: - * Descriptor.msgclass => message_klass - * - * Returns the Ruby class created for this message type. Valid only once the - * message type has been added to a pool. - */ -VALUE Descriptor_msgclass(VALUE _self) { - DEFINE_SELF(Descriptor, self, _self); - if (!upb_def_isfrozen((const upb_def*)self->msgdef)) { - rb_raise(rb_eRuntimeError, - "Cannot fetch message class from a Descriptor not yet in a pool."); - } - if (self->klass == Qnil) { - self->klass = build_class_from_descriptor(self); - } - return self->klass; -} - -// ----------------------------------------------------------------------------- -// FieldDescriptor. -// ----------------------------------------------------------------------------- - -DEFINE_CLASS(FieldDescriptor, "Google::Protobuf::FieldDescriptor"); - -void FieldDescriptor_mark(void* _self) { -} - -void FieldDescriptor_free(void* _self) { - FieldDescriptor* self = _self; - upb_fielddef_unref(self->fielddef, &self->fielddef); - xfree(self); -} - -/* - * call-seq: - * FieldDescriptor.new => field - * - * Returns a new field descriptor. Its name, type, etc. must be set before it is - * added to a message type. - */ -VALUE FieldDescriptor_alloc(VALUE klass) { - FieldDescriptor* self = ALLOC(FieldDescriptor); - VALUE ret = TypedData_Wrap_Struct(klass, &_FieldDescriptor_type, self); - upb_fielddef* fielddef = upb_fielddef_new(&self->fielddef); - upb_fielddef_setpacked(fielddef, false); - self->fielddef = fielddef; - return ret; -} - -void FieldDescriptor_register(VALUE module) { - VALUE klass = rb_define_class_under( - module, "FieldDescriptor", rb_cObject); - rb_define_alloc_func(klass, FieldDescriptor_alloc); - rb_define_method(klass, "name", FieldDescriptor_name, 0); - rb_define_method(klass, "name=", FieldDescriptor_name_set, 1); - rb_define_method(klass, "type", FieldDescriptor_type, 0); - rb_define_method(klass, "type=", FieldDescriptor_type_set, 1); - rb_define_method(klass, "label", FieldDescriptor_label, 0); - rb_define_method(klass, "label=", FieldDescriptor_label_set, 1); - rb_define_method(klass, "number", FieldDescriptor_number, 0); - rb_define_method(klass, "number=", FieldDescriptor_number_set, 1); - rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0); - rb_define_method(klass, "submsg_name=", FieldDescriptor_submsg_name_set, 1); - 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); -} - -/* - * call-seq: - * FieldDescriptor.name => name - * - * Returns the name of this field. - */ -VALUE FieldDescriptor_name(VALUE _self) { - DEFINE_SELF(FieldDescriptor, self, _self); - return rb_str_maybe_null(upb_fielddef_name(self->fielddef)); -} - -/* - * call-seq: - * FieldDescriptor.name = name - * - * Sets the name of this field. Cannot be called once the containing message - * type, if any, is added to a pool. - */ -VALUE FieldDescriptor_name_set(VALUE _self, VALUE str) { - DEFINE_SELF(FieldDescriptor, self, _self); - upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); - const char* name = get_str(str); - CHECK_UPB(upb_fielddef_setname(mut_def, name, &status), - "Error setting FieldDescriptor name"); - return Qnil; -} - -upb_fieldtype_t ruby_to_fieldtype(VALUE type) { - if (TYPE(type) != T_SYMBOL) { - rb_raise(rb_eArgError, "Expected symbol for field type."); - } - - upb_fieldtype_t upb_type = -1; - -#define CONVERT(upb, ruby) \ - if (SYM2ID(type) == rb_intern( # ruby )) { \ - upb_type = UPB_TYPE_ ## upb; \ - } - - CONVERT(FLOAT, float); - CONVERT(DOUBLE, double); - CONVERT(BOOL, bool); - CONVERT(STRING, string); - CONVERT(BYTES, bytes); - CONVERT(MESSAGE, message); - CONVERT(ENUM, enum); - CONVERT(INT32, int32); - CONVERT(INT64, int64); - CONVERT(UINT32, uint32); - CONVERT(UINT64, uint64); - -#undef CONVERT - - if (upb_type == -1) { - rb_raise(rb_eArgError, "Unknown field type."); - } - - return upb_type; -} - -VALUE fieldtype_to_ruby(upb_fieldtype_t type) { - switch (type) { -#define CONVERT(upb, ruby) \ - case UPB_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby )); - CONVERT(FLOAT, float); - CONVERT(DOUBLE, double); - CONVERT(BOOL, bool); - CONVERT(STRING, string); - CONVERT(BYTES, bytes); - CONVERT(MESSAGE, message); - CONVERT(ENUM, enum); - CONVERT(INT32, int32); - CONVERT(INT64, int64); - CONVERT(UINT32, uint32); - CONVERT(UINT64, uint64); -#undef CONVERT - } - return Qnil; -} - -/* - * call-seq: - * FieldDescriptor.type => type - * - * Returns this field's type, as a Ruby symbol, or nil if not yet set. - * - * Valid field types are: - * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string, - * :bytes, :message. - */ -VALUE FieldDescriptor_type(VALUE _self) { - DEFINE_SELF(FieldDescriptor, self, _self); - if (!upb_fielddef_typeisset(self->fielddef)) { - return Qnil; - } - return fieldtype_to_ruby(upb_fielddef_type(self->fielddef)); -} - -/* - * call-seq: - * FieldDescriptor.type = type - * - * Sets this field's type. Cannot be called if field is part of a message type - * already in a pool. - */ -VALUE FieldDescriptor_type_set(VALUE _self, VALUE type) { - DEFINE_SELF(FieldDescriptor, self, _self); - upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); - upb_fielddef_settype(mut_def, ruby_to_fieldtype(type)); - return Qnil; -} - -/* - * call-seq: - * FieldDescriptor.label => label - * - * Returns this field's label (i.e., plurality), as a Ruby symbol. - * - * Valid field labels are: - * :optional, :repeated - */ -VALUE FieldDescriptor_label(VALUE _self) { - DEFINE_SELF(FieldDescriptor, self, _self); - switch (upb_fielddef_label(self->fielddef)) { -#define CONVERT(upb, ruby) \ - case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby )); - - CONVERT(OPTIONAL, optional); - CONVERT(REQUIRED, required); - CONVERT(REPEATED, repeated); - -#undef CONVERT - } - - return Qnil; -} - -/* - * call-seq: - * FieldDescriptor.label = label - * - * Sets the label on this field. Cannot be called if field is part of a message - * type already in a pool. - */ -VALUE FieldDescriptor_label_set(VALUE _self, VALUE label) { - DEFINE_SELF(FieldDescriptor, self, _self); - upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); - if (TYPE(label) != T_SYMBOL) { - rb_raise(rb_eArgError, "Expected symbol for field label."); - } - - upb_label_t upb_label = -1; - -#define CONVERT(upb, ruby) \ - if (SYM2ID(label) == rb_intern( # ruby )) { \ - upb_label = UPB_LABEL_ ## upb; \ - } - - CONVERT(OPTIONAL, optional); - CONVERT(REQUIRED, required); - CONVERT(REPEATED, repeated); - -#undef CONVERT - - if (upb_label == -1) { - rb_raise(rb_eArgError, "Unknown field label."); - } - - upb_fielddef_setlabel(mut_def, upb_label); - - return Qnil; -} - -/* - * call-seq: - * FieldDescriptor.number => number - * - * Returns the tag number for this field. - */ -VALUE FieldDescriptor_number(VALUE _self) { - DEFINE_SELF(FieldDescriptor, self, _self); - return INT2NUM(upb_fielddef_number(self->fielddef)); -} - -/* - * call-seq: - * FieldDescriptor.number = number - * - * Sets the tag number for this field. Cannot be called if field is part of a - * message type already in a pool. - */ -VALUE FieldDescriptor_number_set(VALUE _self, VALUE number) { - DEFINE_SELF(FieldDescriptor, self, _self); - upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); - CHECK_UPB(upb_fielddef_setnumber(mut_def, NUM2INT(number), &status), - "Error setting field number"); - return Qnil; -} - -/* - * call-seq: - * FieldDescriptor.submsg_name => submsg_name - * - * Returns the name of the message or enum type corresponding to this field, if - * it is a message or enum field (respectively), or nil otherwise. This type - * name will be resolved within the context of the pool to which the containing - * message type is added. - */ -VALUE FieldDescriptor_submsg_name(VALUE _self) { - DEFINE_SELF(FieldDescriptor, self, _self); - if (!upb_fielddef_hassubdef(self->fielddef)) { - return Qnil; - } - return rb_str_maybe_null(upb_fielddef_subdefname(self->fielddef)); -} - -/* - * call-seq: - * FieldDescriptor.submsg_name = submsg_name - * - * Sets the name of the message or enum type corresponding to this field, if it - * is a message or enum field (respectively). This type name will be resolved - * within the context of the pool to which the containing message type is added. - * Cannot be called on field that are not of message or enum type, or on fields - * that are part of a message type already added to a pool. - */ -VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value) { - DEFINE_SELF(FieldDescriptor, self, _self); - upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); - if (!upb_fielddef_hassubdef(self->fielddef)) { - rb_raise(rb_eTypeError, "FieldDescriptor does not have subdef."); - } - const char* str = get_str(value); - CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status), - "Error setting submessage name"); - return Qnil; -} - -/* - * call-seq: - * FieldDescriptor.subtype => message_or_enum_descriptor - * - * Returns the message or enum descriptor corresponding to this field's type if - * it is a message or enum field, respectively, or nil otherwise. Cannot be - * called *until* the containing message type is added to a pool (and thus - * resolved). - */ -VALUE FieldDescriptor_subtype(VALUE _self) { - DEFINE_SELF(FieldDescriptor, self, _self); - if (!upb_fielddef_hassubdef(self->fielddef)) { - return Qnil; - } - const upb_def* def = upb_fielddef_subdef(self->fielddef); - if (def == NULL) { - return Qnil; - } - return get_def_obj(def); -} - -/* - * call-seq: - * FieldDescriptor.get(message) => value - * - * Returns the value set for this field on the given message. Raises an - * exception if message is of the wrong type. - */ -VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) { - DEFINE_SELF(FieldDescriptor, self, _self); - 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"); - } - return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef); -} - -/* - * call-seq: - * FieldDescriptor.set(message, value) - * - * Sets the value corresponding to this field to the given value on the given - * message. Raises an exception if message is of the wrong type. Performs the - * ordinary type-checks for field setting. - */ -VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) { - DEFINE_SELF(FieldDescriptor, self, _self); - 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"); - } - layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value); - return Qnil; -} - -// ----------------------------------------------------------------------------- -// EnumDescriptor. -// ----------------------------------------------------------------------------- - -DEFINE_CLASS(EnumDescriptor, "Google::Protobuf::EnumDescriptor"); - -void EnumDescriptor_mark(void* _self) { - EnumDescriptor* self = _self; - rb_gc_mark(self->module); -} - -void EnumDescriptor_free(void* _self) { - EnumDescriptor* self = _self; - upb_enumdef_unref(self->enumdef, &self->enumdef); - xfree(self); -} - -/* - * call-seq: - * EnumDescriptor.new => enum_descriptor - * - * Creates a new, empty, enum descriptor. Must be added to a pool before the - * enum type can be used. The enum type may only be modified prior to adding to - * a pool. - */ -VALUE EnumDescriptor_alloc(VALUE klass) { - EnumDescriptor* self = ALLOC(EnumDescriptor); - VALUE ret = TypedData_Wrap_Struct(klass, &_EnumDescriptor_type, self); - self->enumdef = upb_enumdef_new(&self->enumdef); - self->module = Qnil; - return ret; -} - -void EnumDescriptor_register(VALUE module) { - VALUE klass = rb_define_class_under( - module, "EnumDescriptor", rb_cObject); - rb_define_alloc_func(klass, EnumDescriptor_alloc); - rb_define_method(klass, "name", EnumDescriptor_name, 0); - rb_define_method(klass, "name=", EnumDescriptor_name_set, 1); - rb_define_method(klass, "add_value", EnumDescriptor_add_value, 2); - rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1); - rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1); - 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); -} - -/* - * call-seq: - * EnumDescriptor.name => name - * - * Returns the name of this enum type. - */ -VALUE EnumDescriptor_name(VALUE _self) { - DEFINE_SELF(EnumDescriptor, self, _self); - return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef)); -} - -/* - * call-seq: - * EnumDescriptor.name = name - * - * Sets the name of this enum type. Cannot be called if the enum type has - * already been added to a pool. - */ -VALUE EnumDescriptor_name_set(VALUE _self, VALUE str) { - DEFINE_SELF(EnumDescriptor, self, _self); - upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef); - const char* name = get_str(str); - CHECK_UPB(upb_enumdef_setfullname(mut_def, name, &status), - "Error setting EnumDescriptor name"); - return Qnil; -} - -/* - * call-seq: - * EnumDescriptor.add_value(key, value) - * - * Adds a new key => value mapping to this enum type. Key must be given as a - * Ruby symbol. Cannot be called if the enum type has already been added to a - * pool. Will raise an exception if the key or value is already in use. - */ -VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number) { - DEFINE_SELF(EnumDescriptor, self, _self); - upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef); - const char* name_str = rb_id2name(SYM2ID(name)); - int32_t val = NUM2INT(number); - CHECK_UPB(upb_enumdef_addval(mut_def, name_str, val, &status), - "Error adding value to enum"); - return Qnil; -} - -/* - * call-seq: - * EnumDescriptor.lookup_name(name) => value - * - * Returns the numeric value corresponding to the given key name (as a Ruby - * symbol), or nil if none. - */ -VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) { - DEFINE_SELF(EnumDescriptor, self, _self); - const char* name_str= rb_id2name(SYM2ID(name)); - int32_t val = 0; - if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) { - return INT2NUM(val); - } else { - return Qnil; - } -} - -/* - * call-seq: - * EnumDescriptor.lookup_value(name) => value - * - * Returns the key name (as a Ruby symbol) corresponding to the integer value, - * or nil if none. - */ -VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) { - DEFINE_SELF(EnumDescriptor, self, _self); - int32_t val = NUM2INT(number); - const char* name = upb_enumdef_iton(self->enumdef, val); - if (name != NULL) { - return ID2SYM(rb_intern(name)); - } else { - return Qnil; - } -} - -/* - * call-seq: - * EnumDescriptor.each(&block) - * - * Iterates over key => value mappings in this enum's definition, yielding to - * the block with (key, value) arguments for each one. - */ -VALUE EnumDescriptor_each(VALUE _self) { - DEFINE_SELF(EnumDescriptor, self, _self); - - upb_enum_iter it; - for (upb_enum_begin(&it, self->enumdef); - !upb_enum_done(&it); - upb_enum_next(&it)) { - VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it))); - VALUE number = INT2NUM(upb_enum_iter_number(&it)); - rb_yield_values(2, key, number); - } - - return Qnil; -} - -/* - * call-seq: - * EnumDescriptor.enummodule => module - * - * Returns the Ruby module corresponding to this enum type. Cannot be called - * until the enum descriptor has been added to a pool. - */ -VALUE EnumDescriptor_enummodule(VALUE _self) { - DEFINE_SELF(EnumDescriptor, self, _self); - if (!upb_def_isfrozen((const upb_def*)self->enumdef)) { - rb_raise(rb_eRuntimeError, - "Cannot fetch enum module from an EnumDescriptor not yet " - "in a pool."); - } - if (self->module == Qnil) { - self->module = build_module_from_enumdesc(self); - } - return self->module; -} - -// ----------------------------------------------------------------------------- -// MessageBuilderContext. -// ----------------------------------------------------------------------------- - -DEFINE_CLASS(MessageBuilderContext, - "Google::Protobuf::Internal::MessageBuilderContext"); - -void MessageBuilderContext_mark(void* _self) { - MessageBuilderContext* self = _self; - rb_gc_mark(self->descriptor); -} - -void MessageBuilderContext_free(void* _self) { - MessageBuilderContext* self = _self; - xfree(self); -} - -VALUE MessageBuilderContext_alloc(VALUE klass) { - MessageBuilderContext* self = ALLOC(MessageBuilderContext); - VALUE ret = TypedData_Wrap_Struct( - klass, &_MessageBuilderContext_type, self); - self->descriptor = Qnil; - return ret; -} - -void MessageBuilderContext_register(VALUE module) { - VALUE klass = rb_define_class_under( - module, "MessageBuilderContext", rb_cObject); - rb_define_alloc_func(klass, MessageBuilderContext_alloc); - rb_define_method(klass, "initialize", - MessageBuilderContext_initialize, 1); - rb_define_method(klass, "optional", MessageBuilderContext_optional, -1); - rb_define_method(klass, "required", MessageBuilderContext_required, -1); - rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1); - cMessageBuilderContext = klass; - rb_gc_register_address(&cMessageBuilderContext); -} - -/* - * call-seq: - * MessageBuilderContext.new(desc) => context - * - * Create a new builder context around the given message descriptor. This class - * is intended to serve as a DSL context to be used with #instance_eval. - */ -VALUE MessageBuilderContext_initialize(VALUE _self, VALUE msgdef) { - DEFINE_SELF(MessageBuilderContext, self, _self); - self->descriptor = msgdef; - return Qnil; -} - -static VALUE msgdef_add_field(VALUE msgdef, - const char* label, VALUE name, - VALUE type, VALUE number, - VALUE type_class) { - VALUE fielddef = rb_class_new_instance(0, NULL, cFieldDescriptor); - VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name))); - - rb_funcall(fielddef, rb_intern("label="), 1, ID2SYM(rb_intern(label))); - rb_funcall(fielddef, rb_intern("name="), 1, name_str); - rb_funcall(fielddef, rb_intern("type="), 1, type); - rb_funcall(fielddef, rb_intern("number="), 1, number); - - if (type_class != Qnil) { - if (TYPE(type_class) != T_STRING) { - rb_raise(rb_eArgError, "Expected string for type class"); - } - // Make it an absolute type name by prepending a dot. - type_class = rb_str_append(rb_str_new2("."), type_class); - rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class); - } - - rb_funcall(msgdef, rb_intern("add_field"), 1, fielddef); - return fielddef; -} - -/* - * call-seq: - * MessageBuilderContext.optional(name, type, number, type_class = nil) - * - * Defines a new optional field on this message type with the given type, tag - * number, and type class (for message and enum fields). The type must be a Ruby - * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a - * string, if present (as accepted by FieldDescriptor#submsg_name=). - */ -VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) { - DEFINE_SELF(MessageBuilderContext, self, _self); - - if (argc < 3) { - rb_raise(rb_eArgError, "Expected at least 3 arguments."); - } - VALUE name = argv[0]; - VALUE type = argv[1]; - VALUE number = argv[2]; - VALUE type_class = (argc > 3) ? argv[3] : Qnil; - - return msgdef_add_field(self->descriptor, "optional", - name, type, number, type_class); -} - -/* - * call-seq: - * MessageBuilderContext.required(name, type, number, type_class = nil) - * - * Defines a new required field on this message type with the given type, tag - * number, and type class (for message and enum fields). The type must be a Ruby - * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a - * string, if present (as accepted by FieldDescriptor#submsg_name=). - * - * Proto3 does not have required fields, but this method exists for - * completeness. Any attempt to add a message type with required fields to a - * pool will currently result in an error. - */ -VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) { - DEFINE_SELF(MessageBuilderContext, self, _self); - - if (argc < 3) { - rb_raise(rb_eArgError, "Expected at least 3 arguments."); - } - VALUE name = argv[0]; - VALUE type = argv[1]; - VALUE number = argv[2]; - VALUE type_class = (argc > 3) ? argv[3] : Qnil; - - return msgdef_add_field(self->descriptor, "required", - name, type, number, type_class); -} - -/* - * call-seq: - * MessageBuilderContext.repeated(name, type, number, type_class = nil) - * - * Defines a new repeated field on this message type with the given type, tag - * number, and type class (for message and enum fields). The type must be a Ruby - * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a - * string, if present (as accepted by FieldDescriptor#submsg_name=). - */ -VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) { - DEFINE_SELF(MessageBuilderContext, self, _self); - - if (argc < 3) { - rb_raise(rb_eArgError, "Expected at least 3 arguments."); - } - VALUE name = argv[0]; - VALUE type = argv[1]; - VALUE number = argv[2]; - VALUE type_class = (argc > 3) ? argv[3] : Qnil; - - return msgdef_add_field(self->descriptor, "repeated", - name, type, number, type_class); -} - -// ----------------------------------------------------------------------------- -// EnumBuilderContext. -// ----------------------------------------------------------------------------- - -DEFINE_CLASS(EnumBuilderContext, - "Google::Protobuf::Internal::EnumBuilderContext"); - -void EnumBuilderContext_mark(void* _self) { - EnumBuilderContext* self = _self; - rb_gc_mark(self->enumdesc); -} - -void EnumBuilderContext_free(void* _self) { - EnumBuilderContext* self = _self; - xfree(self); -} - -VALUE EnumBuilderContext_alloc(VALUE klass) { - EnumBuilderContext* self = ALLOC(EnumBuilderContext); - VALUE ret = TypedData_Wrap_Struct( - klass, &_EnumBuilderContext_type, self); - self->enumdesc = Qnil; - return ret; -} - -void EnumBuilderContext_register(VALUE module) { - VALUE klass = rb_define_class_under( - module, "EnumBuilderContext", rb_cObject); - rb_define_alloc_func(klass, EnumBuilderContext_alloc); - rb_define_method(klass, "initialize", - EnumBuilderContext_initialize, 1); - rb_define_method(klass, "value", EnumBuilderContext_value, 2); - cEnumBuilderContext = klass; - rb_gc_register_address(&cEnumBuilderContext); -} - -/* - * call-seq: - * EnumBuilderContext.new(enumdesc) => context - * - * Create a new builder context around the given enum descriptor. This class is - * intended to serve as a DSL context to be used with #instance_eval. - */ -VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdef) { - DEFINE_SELF(EnumBuilderContext, self, _self); - self->enumdesc = enumdef; - return Qnil; -} - -static VALUE enumdef_add_value(VALUE enumdef, - VALUE name, VALUE number) { - rb_funcall(enumdef, rb_intern("add_value"), 2, name, number); - return Qnil; -} - -/* - * call-seq: - * EnumBuilder.add_value(name, number) - * - * Adds the given name => number mapping to the enum type. Name must be a Ruby - * symbol. - */ -VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) { - DEFINE_SELF(EnumBuilderContext, self, _self); - return enumdef_add_value(self->enumdesc, name, number); -} - -// ----------------------------------------------------------------------------- -// Builder. -// ----------------------------------------------------------------------------- - -DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder"); - -void Builder_mark(void* _self) { - Builder* self = _self; - rb_gc_mark(self->pending_list); -} - -void Builder_free(void* _self) { - Builder* self = _self; - xfree(self->defs); - xfree(self); -} - -/* - * call-seq: - * Builder.new => builder - * - * Creates a new Builder. A Builder can accumulate a set of new message and enum - * descriptors and atomically register them into a pool in a way that allows for - * (co)recursive type references. - */ -VALUE Builder_alloc(VALUE klass) { - Builder* self = ALLOC(Builder); - VALUE ret = TypedData_Wrap_Struct( - klass, &_Builder_type, self); - self->pending_list = rb_ary_new(); - self->defs = NULL; - return ret; -} - -void Builder_register(VALUE module) { - VALUE klass = rb_define_class_under(module, "Builder", rb_cObject); - rb_define_alloc_func(klass, Builder_alloc); - rb_define_method(klass, "add_message", Builder_add_message, 1); - rb_define_method(klass, "add_enum", Builder_add_enum, 1); - rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1); - cBuilder = klass; - rb_gc_register_address(&cBuilder); -} - -/* - * call-seq: - * Builder.add_message(name, &block) - * - * Creates a new, empty descriptor with the given name, and invokes the block in - * the context of a MessageBuilderContext on that descriptor. The block can then - * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated - * methods to define the message fields. - * - * This is the recommended, idiomatic way to build message definitions. - */ -VALUE Builder_add_message(VALUE _self, VALUE name) { - DEFINE_SELF(Builder, self, _self); - VALUE msgdef = rb_class_new_instance(0, NULL, cDescriptor); - VALUE ctx = rb_class_new_instance(1, &msgdef, cMessageBuilderContext); - VALUE block = rb_block_proc(); - rb_funcall(msgdef, rb_intern("name="), 1, name); - rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); - rb_ary_push(self->pending_list, msgdef); - return Qnil; -} - -/* - * call-seq: - * Builder.add_enum(name, &block) - * - * Creates a new, empty enum descriptor with the given name, and invokes the block in - * the context of an EnumBuilderContext on that descriptor. The block can then - * call EnumBuilderContext#add_value to define the enum values. - * - * This is the recommended, idiomatic way to build enum definitions. - */ -VALUE Builder_add_enum(VALUE _self, VALUE name) { - DEFINE_SELF(Builder, self, _self); - VALUE enumdef = rb_class_new_instance(0, NULL, cEnumDescriptor); - VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext); - VALUE block = rb_block_proc(); - rb_funcall(enumdef, rb_intern("name="), 1, name); - rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); - rb_ary_push(self->pending_list, enumdef); - return Qnil; -} - -static void validate_msgdef(const upb_msgdef* msgdef) { - // Verify that no required fields exist. proto3 does not support these. - upb_msg_iter it; - for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_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."); - } - } -} - -static void validate_enumdef(const upb_enumdef* enumdef) { - // Verify that an entry exists with integer value 0. (This is the default - // value.) - const char* lookup = upb_enumdef_iton(enumdef, 0); - if (lookup == NULL) { - rb_raise(rb_eTypeError, - "Enum definition does not contain a value for '0'."); - } -} - -/* - * call-seq: - * Builder.finalize_to_pool(pool) - * - * Adds all accumulated message and enum descriptors created in this builder - * context to the given pool. The operation occurs atomically, and all - * descriptors can refer to each other (including in cycles). This is the only - * way to build (co)recursive message definitions. - * - * This method is usually called automatically by DescriptorPool#build after it - * invokes the given user block in the context of the builder. The user should - * not normally need to call this manually because a Builder is not normally - * created manually. - */ -VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) { - DEFINE_SELF(Builder, self, _self); - - DescriptorPool* pool = ruby_to_DescriptorPool(pool_rb); - - REALLOC_N(self->defs, upb_def*, RARRAY_LEN(self->pending_list)); - - for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) { - VALUE def_rb = rb_ary_entry(self->pending_list, i); - if (CLASS_OF(def_rb) == cDescriptor) { - self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef; - validate_msgdef((const upb_msgdef*)self->defs[i]); - } else if (CLASS_OF(def_rb) == cEnumDescriptor) { - self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef; - validate_enumdef((const upb_enumdef*)self->defs[i]); - } - } - - CHECK_UPB(upb_symtab_add(pool->symtab, (upb_def**)self->defs, - RARRAY_LEN(self->pending_list), NULL, &status), - "Unable to add defs to DescriptorPool"); - - for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) { - VALUE def_rb = rb_ary_entry(self->pending_list, i); - add_def_obj(self->defs[i], def_rb); - } - - self->pending_list = rb_ary_new(); - return Qnil; -} diff --git a/ruby/ext/protobuf_c/encode_decode.c b/ruby/ext/protobuf_c/encode_decode.c deleted file mode 100644 index 8aba3c9e..00000000 --- a/ruby/ext/protobuf_c/encode_decode.c +++ /dev/null @@ -1,755 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Parsing. -// ----------------------------------------------------------------------------- - -#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs) - -// Creates a handlerdata that simply contains the offset for this field. -static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) { - size_t* hd_ofs = ALLOC(size_t); - *hd_ofs = ofs; - upb_handlers_addcleanup(h, hd_ofs, free); - return hd_ofs; -} - -typedef struct { - size_t ofs; - const upb_msgdef *md; -} submsg_handlerdata_t; - -// Creates a handlerdata that contains offset and submessage type information. -static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs, - const upb_fielddef* f) { - submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t); - hd->ofs = ofs; - hd->md = upb_fielddef_msgsubdef(f); - upb_handlers_addcleanup(h, hd, free); - return hd; -} - -// A handler that starts a repeated field. Gets the Repeated*Field instance for -// this field (such an instance always exists even in an empty message). -static void *startseq_handler(void* closure, const void* hd) { - MessageHeader* msg = closure; - const size_t *ofs = hd; - return (void*)DEREF(Message_data(msg), *ofs, VALUE); -} - -// Handlers that append primitive values to a repeated field (a regular Ruby -// array for now). -#define DEFINE_APPEND_HANDLER(type, ctype) \ - static bool append##type##_handler(void *closure, const void *hd, \ - ctype val) { \ - VALUE ary = (VALUE)closure; \ - RepeatedField_push_native(ary, &val); \ - return true; \ - } - -DEFINE_APPEND_HANDLER(bool, bool) -DEFINE_APPEND_HANDLER(int32, int32_t) -DEFINE_APPEND_HANDLER(uint32, uint32_t) -DEFINE_APPEND_HANDLER(float, float) -DEFINE_APPEND_HANDLER(int64, int64_t) -DEFINE_APPEND_HANDLER(uint64, uint64_t) -DEFINE_APPEND_HANDLER(double, double) - -// Appends a string to a repeated field (a regular Ruby array for now). -static void* appendstr_handler(void *closure, - const void *hd, - size_t size_hint) { - VALUE ary = (VALUE)closure; - VALUE str = rb_str_new2(""); - rb_enc_associate(str, kRubyStringUtf8Encoding); - RepeatedField_push(ary, str); - return (void*)str; -} - -// Appends a 'bytes' string to a repeated field (a regular Ruby array for now). -static void* appendbytes_handler(void *closure, - const void *hd, - size_t size_hint) { - VALUE ary = (VALUE)closure; - VALUE str = rb_str_new2(""); - rb_enc_associate(str, kRubyString8bitEncoding); - RepeatedField_push(ary, str); - return (void*)str; -} - -// Sets a non-repeated string field in a message. -static void* str_handler(void *closure, - const void *hd, - size_t size_hint) { - MessageHeader* msg = closure; - const size_t *ofs = hd; - VALUE str = rb_str_new2(""); - rb_enc_associate(str, kRubyStringUtf8Encoding); - DEREF(Message_data(msg), *ofs, VALUE) = str; - return (void*)str; -} - -// Sets a non-repeated 'bytes' field in a message. -static void* bytes_handler(void *closure, - const void *hd, - size_t size_hint) { - MessageHeader* msg = closure; - const size_t *ofs = hd; - VALUE str = rb_str_new2(""); - rb_enc_associate(str, kRubyString8bitEncoding); - DEREF(Message_data(msg), *ofs, VALUE) = str; - return (void*)str; -} - -static size_t stringdata_handler(void* closure, const void* hd, - const char* str, size_t len, - const upb_bufhandle* handle) { - VALUE rb_str = (VALUE)closure; - rb_str_cat(rb_str, str, len); - return len; -} - -// Appends a submessage to a repeated field (a regular Ruby array for now). -static void *appendsubmsg_handler(void *closure, const void *hd) { - VALUE ary = (VALUE)closure; - const submsg_handlerdata_t *submsgdata = hd; - VALUE subdesc = - get_def_obj((void*)submsgdata->md); - VALUE subklass = Descriptor_msgclass(subdesc); - - VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass); - RepeatedField_push(ary, submsg_rb); - - MessageHeader* submsg; - TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg); - return submsg; -} - -// Sets a non-repeated submessage field in a message. -static void *submsg_handler(void *closure, const void *hd) { - MessageHeader* msg = closure; - const submsg_handlerdata_t* submsgdata = hd; - VALUE subdesc = - get_def_obj((void*)submsgdata->md); - VALUE subklass = Descriptor_msgclass(subdesc); - - if (DEREF(Message_data(msg), submsgdata->ofs, VALUE) == Qnil) { - DEREF(Message_data(msg), submsgdata->ofs, VALUE) = - rb_class_new_instance(0, NULL, subklass); - } - - VALUE submsg_rb = DEREF(Message_data(msg), submsgdata->ofs, VALUE); - MessageHeader* submsg; - TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg); - return submsg; -} - -static void add_handlers_for_message(const void *closure, upb_handlers *h) { - Descriptor* desc = ruby_to_Descriptor( - get_def_obj((void*)upb_handlers_msgdef(h))); - // Ensure layout exists. We may be invoked to create handlers for a given - // message if we are included as a submsg of another message type before our - // class is actually built, so to work around this, we just create the layout - // (and handlers, in the class-building function) on-demand. - if (desc->layout == NULL) { - desc->layout = create_layout(desc->msgdef); - } - - upb_msg_iter i; - - for (upb_msg_begin(&i, desc->msgdef); - !upb_msg_done(&i); - upb_msg_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - size_t offset = desc->layout->offsets[upb_fielddef_index(f)]; - - if (upb_fielddef_isseq(f)) { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset)); - upb_handlers_setstartseq(h, f, startseq_handler, &attr); - upb_handlerattr_uninit(&attr); - - switch (upb_fielddef_type(f)) { - -#define SET_HANDLER(utype, ltype) \ - case utype: \ - upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \ - break; - - SET_HANDLER(UPB_TYPE_BOOL, bool); - SET_HANDLER(UPB_TYPE_INT32, int32); - SET_HANDLER(UPB_TYPE_UINT32, uint32); - SET_HANDLER(UPB_TYPE_ENUM, int32); - SET_HANDLER(UPB_TYPE_FLOAT, float); - SET_HANDLER(UPB_TYPE_INT64, int64); - SET_HANDLER(UPB_TYPE_UINT64, uint64); - SET_HANDLER(UPB_TYPE_DOUBLE, double); - -#undef SET_HANDLER - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES; - upb_handlers_setstartstr(h, f, is_bytes ? - appendbytes_handler : appendstr_handler, - NULL); - upb_handlers_setstring(h, f, stringdata_handler, NULL); - } - case UPB_TYPE_MESSAGE: { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f)); - upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr); - upb_handlerattr_uninit(&attr); - break; - } - } - } - - switch (upb_fielddef_type(f)) { - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - case UPB_TYPE_DOUBLE: - // The shim writes directly at the given offset (instead of using - // DEREF()) so we need to add the msg overhead. - upb_shim_set(h, f, offset + sizeof(MessageHeader), -1); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES; - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset)); - upb_handlers_setstartstr(h, f, - is_bytes ? bytes_handler : str_handler, - &attr); - upb_handlers_setstring(h, f, stringdata_handler, &attr); - upb_handlerattr_uninit(&attr); - break; - } - case UPB_TYPE_MESSAGE: { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f)); - upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr); - upb_handlerattr_uninit(&attr); - break; - } - } - } -} - -// Creates upb handlers for populating a message. -static const upb_handlers *new_fill_handlers(Descriptor* desc, - const void* owner) { - // TODO(cfallin, haberman): once upb gets a caching/memoization layer for - // handlers, reuse subdef handlers so that e.g. if we already parse - // B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to - // parse A-with-field-of-type-B-with-field-of-type-C. - return upb_handlers_newfrozen(desc->msgdef, owner, - add_handlers_for_message, NULL); -} - -// Constructs the handlers for filling a message's data into an in-memory -// object. -const upb_handlers* get_fill_handlers(Descriptor* desc) { - if (!desc->fill_handlers) { - desc->fill_handlers = - new_fill_handlers(desc, &desc->fill_handlers); - } - return desc->fill_handlers; -} - -// Constructs the upb decoder method for parsing messages of this type. -// This is called from the message class creation code. -const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc, - const void* owner) { - const upb_handlers* handlers = get_fill_handlers(desc); - upb_pbdecodermethodopts opts; - upb_pbdecodermethodopts_init(&opts, handlers); - - const upb_pbdecodermethod *ret = upb_pbdecodermethod_new(&opts, owner); - return ret; -} - -static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) { - if (desc->fill_method == NULL) { - desc->fill_method = new_fillmsg_decodermethod( - desc, &desc->fill_method); - } - return desc->fill_method; -} - -/* - * call-seq: - * MessageClass.decode(data) => message - * - * Decodes the given data (as a string containing bytes in protocol buffers wire - * format) under the interpretration given by this message class's definition - * and returns a message object with the corresponding field values. - */ -VALUE Message_decode(VALUE klass, VALUE data) { - VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); - Descriptor* desc = ruby_to_Descriptor(descriptor); - VALUE msgklass = Descriptor_msgclass(descriptor); - - if (TYPE(data) != T_STRING) { - rb_raise(rb_eArgError, "Expected string for binary protobuf data."); - } - - VALUE msg_rb = rb_class_new_instance(0, NULL, msgklass); - MessageHeader* msg; - TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); - - const upb_pbdecodermethod* method = msgdef_decodermethod(desc); - const upb_handlers* h = upb_pbdecodermethod_desthandlers(method); - upb_pbdecoder decoder; - upb_sink sink; - upb_status status = UPB_STATUS_INIT; - - upb_pbdecoder_init(&decoder, method, &status); - upb_sink_reset(&sink, h, msg); - upb_pbdecoder_resetoutput(&decoder, &sink); - upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), - upb_pbdecoder_input(&decoder)); - - upb_pbdecoder_uninit(&decoder); - if (!upb_ok(&status)) { - rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.", - upb_status_errmsg(&status)); - } - - return msg_rb; -} - -/* - * call-seq: - * MessageClass.decode_json(data) => message - * - * Decodes the given data (as a string containing bytes in protocol buffers wire - * format) under the interpretration given by this message class's definition - * and returns a message object with the corresponding field values. - */ -VALUE Message_decode_json(VALUE klass, VALUE data) { - VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); - Descriptor* desc = ruby_to_Descriptor(descriptor); - VALUE msgklass = Descriptor_msgclass(descriptor); - - if (TYPE(data) != T_STRING) { - rb_raise(rb_eArgError, "Expected string for JSON data."); - } - // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to - // convert, because string handlers pass data directly to message string - // fields. - - VALUE msg_rb = rb_class_new_instance(0, NULL, msgklass); - MessageHeader* msg; - TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); - - upb_status status = UPB_STATUS_INIT; - upb_json_parser parser; - upb_json_parser_init(&parser, &status); - - upb_sink sink; - upb_sink_reset(&sink, get_fill_handlers(desc), msg); - upb_json_parser_resetoutput(&parser, &sink); - upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), - upb_json_parser_input(&parser)); - - upb_json_parser_uninit(&parser); - if (!upb_ok(&status)) { - rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.", - upb_status_errmsg(&status)); - } - - return msg_rb; -} - -// ----------------------------------------------------------------------------- -// Serializing. -// ----------------------------------------------------------------------------- -// -// The code below also comes from upb's prototype Ruby binding, developed by -// haberman@. - -/* stringsink *****************************************************************/ - -// This should probably be factored into a common upb component. - -typedef struct { - upb_byteshandler handler; - upb_bytessink sink; - char *ptr; - size_t len, size; -} stringsink; - -static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { - stringsink *sink = _sink; - sink->len = 0; - return sink; -} - -static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, - size_t len, const upb_bufhandle *handle) { - UPB_UNUSED(hd); - UPB_UNUSED(handle); - - stringsink *sink = _sink; - size_t new_size = sink->size; - - while (sink->len + len > new_size) { - new_size *= 2; - } - - if (new_size != sink->size) { - sink->ptr = realloc(sink->ptr, new_size); - sink->size = new_size; - } - - memcpy(sink->ptr + sink->len, ptr, len); - sink->len += len; - - return len; -} - -void stringsink_init(stringsink *sink) { - upb_byteshandler_init(&sink->handler); - upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); - upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); - - upb_bytessink_reset(&sink->sink, &sink->handler, sink); - - sink->size = 32; - sink->ptr = malloc(sink->size); - sink->len = 0; -} - -void stringsink_uninit(stringsink *sink) { - free(sink->ptr); -} - -/* msgvisitor *****************************************************************/ - -// TODO: If/when we support proto2 semantics in addition to the current proto3 -// semantics, which means that we have true field presence, we will want to -// modify msgvisitor so that it emits all present fields rather than all -// non-default-value fields. -// -// Likewise, when implementing JSON serialization, we may need to have a -// 'verbose' mode that outputs all fields and a 'concise' mode that outputs only -// those with non-default values. - -static void putmsg(VALUE msg, const Descriptor* desc, - upb_sink *sink, int depth); - -static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { - upb_selector_t ret; - bool ok = upb_handlers_getselector(f, type, &ret); - UPB_ASSERT_VAR(ok, ok); - return ret; -} - -static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) { - if (str == Qnil) return; - - assert(BUILTIN_TYPE(str) == RUBY_T_STRING); - upb_sink subsink; - - // Ensure that the string has the correct encoding. We also check at field-set - // time, but the user may have mutated the string object since then. - native_slot_validate_string_encoding(upb_fielddef_type(f), str); - - upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str), - &subsink); - upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str), - RSTRING_LEN(str), NULL); - upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR)); -} - -static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink, - int depth) { - if (submsg == Qnil) return; - - upb_sink subsink; - VALUE descriptor = rb_iv_get(submsg, kDescriptorInstanceVar); - Descriptor* subdesc = ruby_to_Descriptor(descriptor); - - upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); - putmsg(submsg, subdesc, &subsink, depth + 1); - upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG)); -} - -static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink, - int depth) { - if (ary == Qnil) return; - - upb_sink subsink; - - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - - upb_fieldtype_t type = upb_fielddef_type(f); - upb_selector_t sel = 0; - if (upb_fielddef_isprimitive(f)) { - sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - } - - int size = NUM2INT(RepeatedField_length(ary)); - for (int i = 0; i < size; i++) { - void* memory = RepeatedField_index_native(ary, i); - switch (type) { -#define T(upbtypeconst, upbtype, ctype) \ - case upbtypeconst: \ - upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory)); \ - break; - - T(UPB_TYPE_FLOAT, float, float) - T(UPB_TYPE_DOUBLE, double, double) - T(UPB_TYPE_BOOL, bool, int8_t) - case UPB_TYPE_ENUM: - T(UPB_TYPE_INT32, int32, int32_t) - T(UPB_TYPE_UINT32, uint32, uint32_t) - T(UPB_TYPE_INT64, int64, int64_t) - T(UPB_TYPE_UINT64, uint64, uint64_t) - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - putstr(*((VALUE *)memory), f, &subsink); - break; - case UPB_TYPE_MESSAGE: - putsubmsg(*((VALUE *)memory), f, &subsink, depth); - break; - -#undef T - - } - } - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); -} - -static void putmsg(VALUE msg_rb, const Descriptor* desc, - upb_sink *sink, int depth) { - upb_sink_startmsg(sink); - - // Protect against cycles (possible because users may freely reassign message - // and repeated fields) by imposing a maximum recursion depth. - if (depth > UPB_SINK_MAX_NESTING) { - rb_raise(rb_eRuntimeError, - "Maximum recursion depth exceeded during encoding."); - } - - MessageHeader* msg; - TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); - void* msg_data = Message_data(msg); - - upb_msg_iter i; - for (upb_msg_begin(&i, desc->msgdef); - !upb_msg_done(&i); - upb_msg_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - uint32_t offset = desc->layout->offsets[upb_fielddef_index(f)]; - - if (upb_fielddef_isseq(f)) { - VALUE ary = DEREF(msg_data, offset, VALUE); - if (ary != Qnil) { - putary(ary, f, sink, depth); - } - } else if (upb_fielddef_isstring(f)) { - VALUE str = DEREF(msg_data, offset, VALUE); - if (RSTRING_LEN(str) > 0) { - putstr(str, f, sink); - } - } else if (upb_fielddef_issubmsg(f)) { - putsubmsg(DEREF(msg_data, offset, VALUE), f, sink, depth); - } else { - upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - -#define T(upbtypeconst, upbtype, ctype, default_value) \ - case upbtypeconst: { \ - ctype value = DEREF(msg_data, offset, ctype); \ - if (value != default_value) { \ - upb_sink_put##upbtype(sink, sel, value); \ - } \ - } \ - break; - - switch (upb_fielddef_type(f)) { - T(UPB_TYPE_FLOAT, float, float, 0.0) - T(UPB_TYPE_DOUBLE, double, double, 0.0) - T(UPB_TYPE_BOOL, bool, uint8_t, 0) - case UPB_TYPE_ENUM: - T(UPB_TYPE_INT32, int32, int32_t, 0) - T(UPB_TYPE_UINT32, uint32, uint32_t, 0) - T(UPB_TYPE_INT64, int64, int64_t, 0) - T(UPB_TYPE_UINT64, uint64, uint64_t, 0) - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error."); - } - -#undef T - - } - } - - upb_status status; - upb_sink_endmsg(sink, &status); -} - -static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) { - if (desc->pb_serialize_handlers == NULL) { - desc->pb_serialize_handlers = - upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers); - } - return desc->pb_serialize_handlers; -} - -static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) { - if (desc->json_serialize_handlers == NULL) { - desc->json_serialize_handlers = - upb_json_printer_newhandlers( - desc->msgdef, &desc->json_serialize_handlers); - } - return desc->json_serialize_handlers; -} - -/* - * call-seq: - * MessageClass.encode(msg) => bytes - * - * Encodes the given message object to its serialized form in protocol buffers - * wire format. - */ -VALUE Message_encode(VALUE klass, VALUE msg_rb) { - VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); - Descriptor* desc = ruby_to_Descriptor(descriptor); - - stringsink sink; - stringsink_init(&sink); - - const upb_handlers* serialize_handlers = - msgdef_pb_serialize_handlers(desc); - - upb_pb_encoder encoder; - upb_pb_encoder_init(&encoder, serialize_handlers); - upb_pb_encoder_resetoutput(&encoder, &sink.sink); - - putmsg(msg_rb, desc, upb_pb_encoder_input(&encoder), 0); - - VALUE ret = rb_str_new(sink.ptr, sink.len); - - upb_pb_encoder_uninit(&encoder); - stringsink_uninit(&sink); - - return ret; -} - -/* - * call-seq: - * MessageClass.encode_json(msg) => json_string - * - * Encodes the given message object into its serialized JSON representation. - */ -VALUE Message_encode_json(VALUE klass, VALUE msg_rb) { - VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); - Descriptor* desc = ruby_to_Descriptor(descriptor); - - stringsink sink; - stringsink_init(&sink); - - const upb_handlers* serialize_handlers = - msgdef_json_serialize_handlers(desc); - - upb_json_printer printer; - upb_json_printer_init(&printer, serialize_handlers); - upb_json_printer_resetoutput(&printer, &sink.sink); - - putmsg(msg_rb, desc, upb_json_printer_input(&printer), 0); - - VALUE ret = rb_str_new(sink.ptr, sink.len); - - upb_json_printer_uninit(&printer); - stringsink_uninit(&sink); - - return ret; -} - -/* - * call-seq: - * Google::Protobuf.encode(msg) => bytes - * - * Encodes the given message object to protocol buffers wire format. This is an - * alternative to the #encode method on msg's class. - */ -VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb) { - VALUE klass = CLASS_OF(msg_rb); - return Message_encode(klass, msg_rb); -} - -/* - * call-seq: - * Google::Protobuf.encode_json(msg) => json_string - * - * Encodes the given message object to its JSON representation. This is an - * alternative to the #encode_json method on msg's class. - */ -VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb) { - VALUE klass = CLASS_OF(msg_rb); - return Message_encode_json(klass, msg_rb); -} - -/* - * call-seq: - * Google::Protobuf.decode(class, bytes) => msg - * - * Decodes the given bytes as protocol buffers wire format under the - * interpretation given by the given class's message definition. This is an - * alternative to the #decode method on the given class. - */ -VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb) { - return Message_decode(klass, msg_rb); -} - -/* - * call-seq: - * Google::Protobuf.decode_json(class, json_string) => msg - * - * Decodes the given JSON string under the interpretation given by the given - * class's message definition. This is an alternative to the #decode_json method - * on the given class. - */ -VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb) { - return Message_decode_json(klass, msg_rb); -} diff --git a/ruby/ext/protobuf_c/extconf.rb b/ruby/ext/protobuf_c/extconf.rb deleted file mode 100644 index 7f23b1a8..00000000 --- a/ruby/ext/protobuf_c/extconf.rb +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/ruby - -require 'mkmf' - -upb_path = File.absolute_path(File.dirname($0)) + "/../../../upb" -libs = ["upb_pic", "upb.pb_pic", "upb.json_pic"] -system("cd #{upb_path}; make " + libs.map{|l| "lib/lib#{l}.a"}.join(" ")) - -$CFLAGS += " -O3 -std=c99 -Wno-unused-function -DNDEBUG" - -find_header("upb/upb.h", upb_path) or - raise "Can't find upb headers" -find_library("upb_pic", "upb_msgdef_new", upb_path + "/lib") or - raise "Can't find upb lib" -find_library("upb.pb_pic", "upb_pbdecoder_init", upb_path + "/lib") or - raise "Can't find upb.pb lib" -find_library("upb.json_pic", "upb_json_printer_init", upb_path + "/lib") or - raise "Can't find upb.pb lib" - -$objs = ["protobuf.o", "defs.o", "storage.o", "message.o", - "repeated_field.o", "encode_decode.o"] - -create_makefile("protobuf_c") diff --git a/ruby/ext/protobuf_c/message.c b/ruby/ext/protobuf_c/message.c deleted file mode 100644 index 105b7807..00000000 --- a/ruby/ext/protobuf_c/message.c +++ /dev/null @@ -1,463 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Class/module creation from msgdefs and enumdefs, respectively. -// ----------------------------------------------------------------------------- - -void* Message_data(void* msg) { - return ((uint8_t *)msg) + sizeof(MessageHeader); -} - -void Message_mark(void* _self) { - MessageHeader* self = (MessageHeader *)_self; - layout_mark(self->descriptor->layout, Message_data(self)); -} - -void Message_free(void* self) { - xfree(self); -} - -rb_data_type_t Message_type = { - "Message", - { Message_mark, Message_free, NULL }, -}; - -VALUE Message_alloc(VALUE klass) { - VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); - Descriptor* desc = ruby_to_Descriptor(descriptor); - MessageHeader* msg = (MessageHeader*)ALLOC_N( - uint8_t, sizeof(MessageHeader) + desc->layout->size); - memset(Message_data(msg), 0, desc->layout->size); - - // We wrap first so that everything in the message object is GC-rooted in case - // a collection happens during object creation in layout_init(). - VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg); - msg->descriptor = desc; - rb_iv_set(ret, kDescriptorInstanceVar, descriptor); - - layout_init(desc->layout, Message_data(msg)); - - return ret; -} - -/* - * call-seq: - * Message.method_missing(*args) - * - * Provides accessors and setters for message fields according to their field - * names. For any field whose name does not conflict with a built-in method, an - * accessor is provided with the same name as the field, and a setter is - * provided with the name of the field plus the '=' suffix. Thus, given a - * message instance 'msg' with field 'foo', the following code is valid: - * - * msg.foo = 42 - * puts msg.foo - */ -VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - if (argc < 1) { - rb_raise(rb_eArgError, "Expected method name as first argument."); - } - VALUE method_name = argv[0]; - if (!SYMBOL_P(method_name)) { - rb_raise(rb_eArgError, "Expected symbol as method name."); - } - VALUE method_str = rb_id2str(SYM2ID(method_name)); - char* name = RSTRING_PTR(method_str); - size_t name_len = RSTRING_LEN(method_str); - bool setter = false; - - // Setters have names that end in '='. - if (name[name_len - 1] == '=') { - setter = true; - name_len--; - } - - const upb_fielddef* f = upb_msgdef_ntof(self->descriptor->msgdef, - name, name_len); - - if (f == NULL) { - rb_raise(rb_eArgError, "Unknown field"); - } - - if (setter) { - if (argc < 2) { - rb_raise(rb_eArgError, "No value provided to setter."); - } - layout_set(self->descriptor->layout, Message_data(self), f, argv[1]); - return Qnil; - } else { - return layout_get(self->descriptor->layout, Message_data(self), f); - } -} - -int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - - if (!SYMBOL_P(key)) { - rb_raise(rb_eArgError, - "Expected symbols as hash keys in initialization map."); - } - - VALUE method_str = rb_id2str(SYM2ID(key)); - char* name = RSTRING_PTR(method_str); - const upb_fielddef* f = upb_msgdef_ntofz(self->descriptor->msgdef, name); - if (f == NULL) { - rb_raise(rb_eArgError, - "Unknown field name in initialization map entry."); - } - - if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) { - if (TYPE(val) != T_ARRAY) { - rb_raise(rb_eArgError, - "Expected array as initializer value for repeated field."); - } - VALUE ary = layout_get(self->descriptor->layout, Message_data(self), f); - for (int i = 0; i < RARRAY_LEN(val); i++) { - RepeatedField_push(ary, rb_ary_entry(val, i)); - } - } else { - layout_set(self->descriptor->layout, Message_data(self), f, val); - } - return 0; -} - -/* - * call-seq: - * Message.new(kwargs) => new_message - * - * Creates a new instance of the given message class. Keyword arguments may be - * provided with keywords corresponding to field names. - * - * Note that no literal Message class exists. Only concrete classes per message - * type exist, as provided by the #msgclass method on Descriptors after they - * have been added to a pool. The method definitions described here on the - * Message class are provided on each concrete message class. - */ -VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) { - if (argc == 0) { - return Qnil; - } - if (argc != 1) { - rb_raise(rb_eArgError, "Expected 0 or 1 arguments."); - } - VALUE hash_args = argv[0]; - if (TYPE(hash_args) != T_HASH) { - rb_raise(rb_eArgError, "Expected hash arguments."); - } - - rb_hash_foreach(hash_args, Message_initialize_kwarg, _self); - return Qnil; -} - -/* - * call-seq: - * Message.dup => new_message - * - * Performs a shallow copy of this message and returns the new copy. - */ -VALUE Message_dup(VALUE _self) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - - VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self)); - MessageHeader* new_msg_self; - TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self); - - layout_dup(self->descriptor->layout, - Message_data(new_msg_self), - Message_data(self)); - - return new_msg; -} - -// Internal only; used by Google::Protobuf.deep_copy. -VALUE Message_deep_copy(VALUE _self) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - - VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self)); - MessageHeader* new_msg_self; - TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self); - - layout_deep_copy(self->descriptor->layout, - Message_data(new_msg_self), - Message_data(self)); - - return new_msg; -} - -/* - * call-seq: - * Message.==(other) => boolean - * - * Performs a deep comparison of this message with another. Messages are equal - * if they have the same type and if each field is equal according to the :== - * method's semantics (a more efficient comparison may actually be done if the - * field is of a primitive type). - */ -VALUE Message_eq(VALUE _self, VALUE _other) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - - MessageHeader* other; - TypedData_Get_Struct(_other, MessageHeader, &Message_type, other); - - if (self->descriptor != other->descriptor) { - return Qfalse; - } - - return layout_eq(self->descriptor->layout, - Message_data(self), - Message_data(other)); -} - -/* - * call-seq: - * Message.hash => hash_value - * - * Returns a hash value that represents this message's field values. - */ -VALUE Message_hash(VALUE _self) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - - return layout_hash(self->descriptor->layout, Message_data(self)); -} - -/* - * call-seq: - * Message.inspect => string - * - * Returns a human-readable string representing this message. It will be - * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each - * field's value is represented according to its own #inspect method. - */ -VALUE Message_inspect(VALUE _self) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - - VALUE str = rb_str_new2("<"); - str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self)))); - str = rb_str_cat2(str, ": "); - str = rb_str_append(str, layout_inspect( - self->descriptor->layout, Message_data(self))); - str = rb_str_cat2(str, ">"); - return str; -} - -/* - * call-seq: - * Message.[](index) => value - * - * Accesses a field's value by field name. The provided field name should be a - * string. - */ -VALUE Message_index(VALUE _self, VALUE field_name) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - Check_Type(field_name, T_STRING); - const upb_fielddef* field = - upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name)); - if (field == NULL) { - return Qnil; - } - return layout_get(self->descriptor->layout, Message_data(self), field); -} - -/* - * call-seq: - * Message.[]=(index, value) - * - * Sets a field's value by field name. The provided field name should be a - * string. - */ -VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) { - MessageHeader* self; - TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); - Check_Type(field_name, T_STRING); - const upb_fielddef* field = - upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name)); - if (field == NULL) { - rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name)); - } - layout_set(self->descriptor->layout, Message_data(self), field, value); - return Qnil; -} - -/* - * call-seq: - * Message.descriptor => descriptor - * - * Class method that returns the Descriptor instance corresponding to this - * message class's type. - */ -VALUE Message_descriptor(VALUE klass) { - return rb_iv_get(klass, kDescriptorInstanceVar); -} - -VALUE build_class_from_descriptor(Descriptor* desc) { - if (desc->layout == NULL) { - desc->layout = create_layout(desc->msgdef); - } - if (desc->fill_method == NULL) { - desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method); - } - - const char* name = upb_msgdef_fullname(desc->msgdef); - if (name == NULL) { - rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name."); - } - - VALUE 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_iv_set(klass, kDescriptorInstanceVar, get_def_obj(desc->msgdef)); - rb_define_alloc_func(klass, Message_alloc); - rb_define_method(klass, "method_missing", - Message_method_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, "hash", Message_hash, 0); - rb_define_method(klass, "inspect", 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; -} - -/* - * call-seq: - * Enum.lookup(number) => name - * - * This module method, provided on each generated enum module, looks up an enum - * value by number and returns its name as a Ruby symbol, or nil if not found. - */ -VALUE enum_lookup(VALUE self, VALUE number) { - int32_t num = NUM2INT(number); - VALUE desc = rb_iv_get(self, kDescriptorInstanceVar); - EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc); - - const char* name = upb_enumdef_iton(enumdesc->enumdef, num); - if (name == NULL) { - return Qnil; - } else { - return ID2SYM(rb_intern(name)); - } -} - -/* - * call-seq: - * Enum.resolve(name) => number - * - * This module method, provided on each generated enum module, looks up an enum - * value by name (as a Ruby symbol) and returns its name, or nil if not found. - */ -VALUE enum_resolve(VALUE self, VALUE sym) { - const char* name = rb_id2name(SYM2ID(sym)); - VALUE desc = rb_iv_get(self, kDescriptorInstanceVar); - EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc); - - int32_t num = 0; - bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num); - if (!found) { - return Qnil; - } else { - return INT2NUM(num); - } -} - -/* - * call-seq: - * Enum.descriptor - * - * This module method, provided on each generated enum module, returns the - * EnumDescriptor corresponding to this enum type. - */ -VALUE enum_descriptor(VALUE self) { - return rb_iv_get(self, kDescriptorInstanceVar); -} - -VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) { - VALUE mod = rb_define_module_id( - rb_intern(upb_enumdef_fullname(enumdesc->enumdef))); - - upb_enum_iter it; - for (upb_enum_begin(&it, enumdesc->enumdef); - !upb_enum_done(&it); - upb_enum_next(&it)) { - 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, - "Enum value '%s' does not start with an uppercase letter " - "as is required for Ruby constants.", - name); - } - rb_define_const(mod, name, INT2NUM(value)); - } - - rb_define_singleton_method(mod, "lookup", enum_lookup, 1); - rb_define_singleton_method(mod, "resolve", enum_resolve, 1); - rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0); - rb_iv_set(mod, kDescriptorInstanceVar, get_def_obj(enumdesc->enumdef)); - - return mod; -} - -/* - * call-seq: - * Google::Protobuf.deep_copy(obj) => copy_of_obj - * - * Performs a deep copy of either a RepeatedField instance or a message object, - * recursively copying its members. - */ -VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) { - VALUE klass = CLASS_OF(obj); - if (klass == cRepeatedField) { - return RepeatedField_deep_copy(obj); - } else { - return Message_deep_copy(obj); - } -} diff --git a/ruby/ext/protobuf_c/protobuf.c b/ruby/ext/protobuf_c/protobuf.c deleted file mode 100644 index d5862284..00000000 --- a/ruby/ext/protobuf_c/protobuf.c +++ /dev/null @@ -1,102 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor -// instances. -// ----------------------------------------------------------------------------- - -// This is a hash table from def objects (encoded by converting pointers to -// Ruby integers) to MessageDef/EnumDef instances (as Ruby values). -VALUE upb_def_to_ruby_obj_map; - -void add_def_obj(const void* def, VALUE value) { - rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value); -} - -VALUE get_def_obj(const void* def) { - return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def)); -} - -// ----------------------------------------------------------------------------- -// Utilities. -// ----------------------------------------------------------------------------- - -// Raises a Ruby error if |status| is not OK, using its error message. -void check_upb_status(const upb_status* status, const char* msg) { - if (!upb_ok(status)) { - rb_raise(rb_eRuntimeError, "%s: %s\n", msg, upb_status_errmsg(status)); - } -} - -// String encodings: we look these up once, at load time, and then cache them -// here. -rb_encoding* kRubyStringUtf8Encoding; -rb_encoding* kRubyStringASCIIEncoding; -rb_encoding* kRubyString8bitEncoding; - -// ----------------------------------------------------------------------------- -// Initialization/entry point. -// ----------------------------------------------------------------------------- - -// This must be named "Init_protobuf_c" because the Ruby module is named -// "protobuf_c" -- the VM looks for this symbol in our .so. -void Init_protobuf_c() { - VALUE google = rb_define_module("Google"); - VALUE protobuf = rb_define_module_under(google, "Protobuf"); - VALUE internal = rb_define_module_under(protobuf, "Internal"); - DescriptorPool_register(protobuf); - Descriptor_register(protobuf); - FieldDescriptor_register(protobuf); - EnumDescriptor_register(protobuf); - MessageBuilderContext_register(internal); - EnumBuilderContext_register(internal); - Builder_register(internal); - RepeatedField_register(protobuf); - - rb_define_singleton_method(protobuf, "encode", Google_Protobuf_encode, 1); - rb_define_singleton_method(protobuf, "decode", Google_Protobuf_decode, 2); - rb_define_singleton_method(protobuf, "encode_json", - Google_Protobuf_encode_json, 1); - rb_define_singleton_method(protobuf, "decode_json", - Google_Protobuf_decode_json, 2); - - rb_define_singleton_method(protobuf, "deep_copy", - Google_Protobuf_deep_copy, 1); - - kRubyStringUtf8Encoding = rb_utf8_encoding(); - kRubyStringASCIIEncoding = rb_usascii_encoding(); - kRubyString8bitEncoding = rb_ascii8bit_encoding(); - - upb_def_to_ruby_obj_map = rb_hash_new(); - rb_gc_register_address(&upb_def_to_ruby_obj_map); -} diff --git a/ruby/ext/protobuf_c/protobuf.h b/ruby/ext/protobuf_c/protobuf.h deleted file mode 100644 index a7f6f539..00000000 --- a/ruby/ext/protobuf_c/protobuf.h +++ /dev/null @@ -1,404 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ -#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ - -#include <ruby/ruby.h> -#include <ruby/vm.h> -#include <ruby/encoding.h> - -#include "upb/def.h" -#include "upb/handlers.h" -#include "upb/pb/decoder.h" -#include "upb/pb/encoder.h" -#include "upb/pb/glue.h" -#include "upb/json/parser.h" -#include "upb/json/printer.h" -#include "upb/shim/shim.h" -#include "upb/symtab.h" - -// Forward decls. -struct DescriptorPool; -struct Descriptor; -struct FieldDescriptor; -struct EnumDescriptor; -struct MessageLayout; -struct MessageHeader; -struct MessageBuilderContext; -struct EnumBuilderContext; -struct Builder; - -typedef struct DescriptorPool DescriptorPool; -typedef struct Descriptor Descriptor; -typedef struct FieldDescriptor FieldDescriptor; -typedef struct EnumDescriptor EnumDescriptor; -typedef struct MessageLayout MessageLayout; -typedef struct MessageHeader MessageHeader; -typedef struct MessageBuilderContext MessageBuilderContext; -typedef struct EnumBuilderContext EnumBuilderContext; -typedef struct Builder Builder; - -/* - It can be a bit confusing how the C structs defined below and the Ruby - objects interact and hold references to each other. First, a few principles: - - - Ruby's "TypedData" abstraction lets a Ruby VALUE hold a pointer to a C - struct (or arbitrary memory chunk), own it, and free it when collected. - Thus, each struct below will have a corresponding Ruby object - wrapping/owning it. - - - To get back from an underlying upb {msg,enum}def to the Ruby object, we - keep a global hashmap, accessed by get_def_obj/add_def_obj below. - - The in-memory structure is then something like: - - Ruby | upb - | - DescriptorPool ------------|-----------> upb_symtab____________________ - | | (message types) \ - | v \ - Descriptor ---------------|-----------> upb_msgdef (enum types)| - |--> msgclass | | ^ | - | (dynamically built) | | | (submsg fields) | - |--> MessageLayout | | | / - |--------------------------|> decoder method| | / - \--------------------------|> serialize | | / - | handlers v | / - FieldDescriptor -----------|-----------> upb_fielddef / - | | / - | v (enum fields) / - EnumDescriptor ------------|-----------> upb_enumdef <----------' - | - | - ^ | \___/ - `---------------|-----------------' (get_def_obj map) - */ - -// ----------------------------------------------------------------------------- -// Ruby class structure definitions. -// ----------------------------------------------------------------------------- - -struct DescriptorPool { - upb_symtab* symtab; -}; - -struct Descriptor { - const upb_msgdef* msgdef; - MessageLayout* layout; - VALUE klass; // begins as nil - const upb_handlers* fill_handlers; - const upb_pbdecodermethod* fill_method; - const upb_handlers* pb_serialize_handlers; - const upb_handlers* json_serialize_handlers; -}; - -struct FieldDescriptor { - const upb_fielddef* fielddef; -}; - -struct EnumDescriptor { - const upb_enumdef* enumdef; - VALUE module; // begins as nil -}; - -struct MessageBuilderContext { - VALUE descriptor; -}; - -struct EnumBuilderContext { - VALUE enumdesc; -}; - -struct Builder { - VALUE pending_list; - upb_def** defs; // used only while finalizing -}; - -extern VALUE cDescriptorPool; -extern VALUE cDescriptor; -extern VALUE cFieldDescriptor; -extern VALUE cEnumDescriptor; -extern VALUE cMessageBuilderContext; -extern VALUE cEnumBuilderContext; -extern VALUE cBuilder; - -extern const char* kDescriptorInstanceVar; - -// We forward-declare all of the Ruby method implementations here because we -// sometimes call the methods directly across .c files, rather than going -// through Ruby's method dispatching (e.g. during message parse). It's cleaner -// to keep the list of object methods together than to split them between -// static-in-file definitions and header declarations. - -void DescriptorPool_mark(void* _self); -void DescriptorPool_free(void* _self); -VALUE DescriptorPool_alloc(VALUE klass); -void DescriptorPool_register(VALUE module); -DescriptorPool* ruby_to_DescriptorPool(VALUE value); -VALUE DescriptorPool_add(VALUE _self, VALUE def); -VALUE DescriptorPool_build(VALUE _self); -VALUE DescriptorPool_lookup(VALUE _self, VALUE name); -VALUE DescriptorPool_generated_pool(VALUE _self); - -void Descriptor_mark(void* _self); -void Descriptor_free(void* _self); -VALUE Descriptor_alloc(VALUE klass); -void Descriptor_register(VALUE module); -Descriptor* ruby_to_Descriptor(VALUE value); -VALUE Descriptor_name(VALUE _self); -VALUE Descriptor_name_set(VALUE _self, VALUE str); -VALUE Descriptor_each(VALUE _self); -VALUE Descriptor_lookup(VALUE _self, VALUE name); -VALUE Descriptor_add_field(VALUE _self, VALUE obj); -VALUE Descriptor_msgclass(VALUE _self); -extern const rb_data_type_t _Descriptor_type; - -void FieldDescriptor_mark(void* _self); -void FieldDescriptor_free(void* _self); -VALUE FieldDescriptor_alloc(VALUE klass); -void FieldDescriptor_register(VALUE module); -FieldDescriptor* ruby_to_FieldDescriptor(VALUE value); -VALUE FieldDescriptor_name(VALUE _self); -VALUE FieldDescriptor_name_set(VALUE _self, VALUE str); -VALUE FieldDescriptor_type(VALUE _self); -VALUE FieldDescriptor_type_set(VALUE _self, VALUE type); -VALUE FieldDescriptor_label(VALUE _self); -VALUE FieldDescriptor_label_set(VALUE _self, VALUE label); -VALUE FieldDescriptor_number(VALUE _self); -VALUE FieldDescriptor_number_set(VALUE _self, VALUE number); -VALUE FieldDescriptor_submsg_name(VALUE _self); -VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value); -VALUE FieldDescriptor_subtype(VALUE _self); -VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb); -VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value); -upb_fieldtype_t ruby_to_fieldtype(VALUE type); -VALUE fieldtype_to_ruby(upb_fieldtype_t type); - -void EnumDescriptor_mark(void* _self); -void EnumDescriptor_free(void* _self); -VALUE EnumDescriptor_alloc(VALUE klass); -void EnumDescriptor_register(VALUE module); -EnumDescriptor* ruby_to_EnumDescriptor(VALUE value); -VALUE EnumDescriptor_name(VALUE _self); -VALUE EnumDescriptor_name_set(VALUE _self, VALUE str); -VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number); -VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name); -VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number); -VALUE EnumDescriptor_each(VALUE _self); -VALUE EnumDescriptor_enummodule(VALUE _self); -extern const rb_data_type_t _EnumDescriptor_type; - -void MessageBuilderContext_mark(void* _self); -void MessageBuilderContext_free(void* _self); -VALUE MessageBuilderContext_alloc(VALUE klass); -void MessageBuilderContext_register(VALUE module); -MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value); -VALUE MessageBuilderContext_initialize(VALUE _self, VALUE descriptor); -VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self); -VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self); -VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self); - -void EnumBuilderContext_mark(void* _self); -void EnumBuilderContext_free(void* _self); -VALUE EnumBuilderContext_alloc(VALUE klass); -void EnumBuilderContext_register(VALUE module); -EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE value); -VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdesc); -VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number); - -void Builder_mark(void* _self); -void Builder_free(void* _self); -VALUE Builder_alloc(VALUE klass); -void Builder_register(VALUE module); -Builder* ruby_to_Builder(VALUE value); -VALUE Builder_add_message(VALUE _self, VALUE name); -VALUE Builder_add_enum(VALUE _self, VALUE name); -VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb); - -// ----------------------------------------------------------------------------- -// Native slot storage abstraction. -// ----------------------------------------------------------------------------- - -size_t native_slot_size(upb_fieldtype_t type); -void native_slot_set(upb_fieldtype_t type, - VALUE type_class, - void* memory, - VALUE value); -VALUE native_slot_get(upb_fieldtype_t type, - VALUE type_class, - void* memory); -void native_slot_init(upb_fieldtype_t type, void* memory); -void native_slot_mark(upb_fieldtype_t type, void* memory); -void native_slot_dup(upb_fieldtype_t type, void* to, void* from); -void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from); -bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2); - -void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value); - -extern rb_encoding* kRubyStringUtf8Encoding; -extern rb_encoding* kRubyStringASCIIEncoding; -extern rb_encoding* kRubyString8bitEncoding; - -// ----------------------------------------------------------------------------- -// Repeated field container type. -// ----------------------------------------------------------------------------- - -typedef struct { - upb_fieldtype_t field_type; - VALUE field_type_class; - void* elements; - int size; - int capacity; -} RepeatedField; - -void RepeatedField_mark(void* self); -void RepeatedField_free(void* self); -VALUE RepeatedField_alloc(VALUE klass); -VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self); -void RepeatedField_register(VALUE module); - -extern const rb_data_type_t RepeatedField_type; -extern VALUE cRepeatedField; - -RepeatedField* ruby_to_RepeatedField(VALUE value); - -void RepeatedField_register(VALUE module); -VALUE RepeatedField_each(VALUE _self); -VALUE RepeatedField_index(VALUE _self, VALUE _index); -void* RepeatedField_index_native(VALUE _self, int index); -VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val); -void RepeatedField_reserve(RepeatedField* self, int new_size); -VALUE RepeatedField_push(VALUE _self, VALUE val); -void RepeatedField_push_native(VALUE _self, void* data); -VALUE RepeatedField_pop(VALUE _self); -VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self); -VALUE RepeatedField_replace(VALUE _self, VALUE list); -VALUE RepeatedField_clear(VALUE _self); -VALUE RepeatedField_length(VALUE _self); -VALUE RepeatedField_dup(VALUE _self); -VALUE RepeatedField_deep_copy(VALUE _self); -VALUE RepeatedField_eq(VALUE _self, VALUE _other); -VALUE RepeatedField_hash(VALUE _self); -VALUE RepeatedField_inspect(VALUE _self); -VALUE RepeatedField_plus(VALUE _self, VALUE list); - -// ----------------------------------------------------------------------------- -// Message layout / storage. -// ----------------------------------------------------------------------------- - -struct MessageLayout { - const upb_msgdef* msgdef; - size_t* offsets; - size_t size; -}; - -MessageLayout* create_layout(const upb_msgdef* msgdef); -void free_layout(MessageLayout* layout); -VALUE layout_get(MessageLayout* layout, - void* storage, - const upb_fielddef* field); -void layout_set(MessageLayout* layout, - void* storage, - const upb_fielddef* field, - VALUE val); -void layout_init(MessageLayout* layout, void* storage); -void layout_mark(MessageLayout* layout, void* storage); -void layout_dup(MessageLayout* layout, void* to, void* from); -void layout_deep_copy(MessageLayout* layout, void* to, void* from); -VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2); -VALUE layout_hash(MessageLayout* layout, void* storage); -VALUE layout_inspect(MessageLayout* layout, void* storage); - -// ----------------------------------------------------------------------------- -// Message class creation. -// ----------------------------------------------------------------------------- - -struct MessageHeader { - Descriptor* descriptor; // kept alive by self.class.descriptor reference. - // Data comes after this. -}; - -extern rb_data_type_t Message_type; - -VALUE build_class_from_descriptor(Descriptor* descriptor); -void* Message_data(void* msg); -void Message_mark(void* self); -void Message_free(void* self); -VALUE Message_alloc(VALUE klass); -VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self); -VALUE Message_initialize(int argc, VALUE* argv, VALUE _self); -VALUE Message_dup(VALUE _self); -VALUE Message_deep_copy(VALUE _self); -VALUE Message_eq(VALUE _self, VALUE _other); -VALUE Message_hash(VALUE _self); -VALUE Message_inspect(VALUE _self); -VALUE Message_index(VALUE _self, VALUE field_name); -VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value); -VALUE Message_descriptor(VALUE klass); -VALUE Message_decode(VALUE klass, VALUE data); -VALUE Message_encode(VALUE klass, VALUE msg_rb); -VALUE Message_decode_json(VALUE klass, VALUE data); -VALUE Message_encode_json(VALUE klass, VALUE msg_rb); - -VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb); -VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb); -VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb); -VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb); - -VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj); - -VALUE build_module_from_enumdesc(EnumDescriptor* enumdef); -VALUE enum_lookup(VALUE self, VALUE number); -VALUE enum_resolve(VALUE self, VALUE sym); - -const upb_pbdecodermethod *new_fillmsg_decodermethod( - Descriptor* descriptor, const void *owner); - -// ----------------------------------------------------------------------------- -// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor -// instances. -// ----------------------------------------------------------------------------- -void add_def_obj(const void* def, VALUE value); -VALUE get_def_obj(const void* def); - -// ----------------------------------------------------------------------------- -// Utilities. -// ----------------------------------------------------------------------------- - -void check_upb_status(const upb_status* status, const char* msg); - -#define CHECK_UPB(code, msg) do { \ - upb_status status = UPB_STATUS_INIT; \ - code; \ - check_upb_status(&status, msg); \ -} while (0) - -#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ diff --git a/ruby/ext/protobuf_c/repeated_field.c b/ruby/ext/protobuf_c/repeated_field.c deleted file mode 100644 index 6bd13b07..00000000 --- a/ruby/ext/protobuf_c/repeated_field.c +++ /dev/null @@ -1,597 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Repeated field container type. -// ----------------------------------------------------------------------------- - -const rb_data_type_t RepeatedField_type = { - "Google::Protobuf::RepeatedField", - { RepeatedField_mark, RepeatedField_free, NULL }, -}; - -VALUE cRepeatedField; - -RepeatedField* ruby_to_RepeatedField(VALUE _self) { - RepeatedField* self; - TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self); - return self; -} - -/* - * call-seq: - * RepeatedField.each(&block) - * - * Invokes the block once for each element of the repeated field. RepeatedField - * also includes Enumerable; combined with this method, the repeated field thus - * acts like an ordinary Ruby sequence. - */ -VALUE RepeatedField_each(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - upb_fieldtype_t field_type = self->field_type; - VALUE field_type_class = self->field_type_class; - int element_size = native_slot_size(field_type); - - size_t off = 0; - for (int i = 0; i < self->size; i++, off += element_size) { - void* memory = (void *) (((uint8_t *)self->elements) + off); - VALUE val = native_slot_get(field_type, field_type_class, memory); - rb_yield(val); - } - return Qnil; -} - -/* - * call-seq: - * RepeatedField.[](index) => value - * - * Accesses the element at the given index. Throws an exception on out-of-bounds - * errors. - */ -VALUE RepeatedField_index(VALUE _self, VALUE _index) { - RepeatedField* self = ruby_to_RepeatedField(_self); - int element_size = native_slot_size(self->field_type); - upb_fieldtype_t field_type = self->field_type; - VALUE field_type_class = self->field_type_class; - - int index = NUM2INT(_index); - if (index < 0 || index >= self->size) { - rb_raise(rb_eRangeError, "Index out of range"); - } - - void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); - return native_slot_get(field_type, field_type_class, memory); -} - -/* - * call-seq: - * RepeatedField.[]=(index, value) - * - * Sets the element at the given index. On out-of-bounds assignments, extends - * the array and fills the hole (if any) with default values. - */ -VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) { - RepeatedField* self = ruby_to_RepeatedField(_self); - upb_fieldtype_t field_type = self->field_type; - VALUE field_type_class = self->field_type_class; - int element_size = native_slot_size(field_type); - - int index = NUM2INT(_index); - if (index < 0 || index >= (INT_MAX - 1)) { - rb_raise(rb_eRangeError, "Index out of range"); - } - if (index >= self->size) { - RepeatedField_reserve(self, index + 1); - upb_fieldtype_t field_type = self->field_type; - int element_size = native_slot_size(field_type); - for (int i = self->size; i <= index; i++) { - void* elem = (void *)(((uint8_t *)self->elements) + i * element_size); - native_slot_init(field_type, elem); - } - self->size = index + 1; - } - - void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); - native_slot_set(field_type, field_type_class, memory, val); - return Qnil; -} - -static int kInitialSize = 8; - -void RepeatedField_reserve(RepeatedField* self, int new_size) { - if (new_size <= self->capacity) { - return; - } - if (self->capacity == 0) { - self->capacity = kInitialSize; - } - while (self->capacity < new_size) { - self->capacity *= 2; - } - void* old_elems = self->elements; - int elem_size = native_slot_size(self->field_type); - self->elements = ALLOC_N(uint8_t, elem_size * self->capacity); - if (old_elems != NULL) { - memcpy(self->elements, old_elems, self->size * elem_size); - xfree(old_elems); - } -} - -/* - * call-seq: - * RepeatedField.push(value) - * - * Adds a new element to the repeated field. - */ -VALUE RepeatedField_push(VALUE _self, VALUE val) { - RepeatedField* self = ruby_to_RepeatedField(_self); - upb_fieldtype_t field_type = self->field_type; - int element_size = native_slot_size(field_type); - RepeatedField_reserve(self, self->size + 1); - int index = self->size; - void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); - native_slot_set(field_type, self->field_type_class, memory, val); - // native_slot_set may raise an error; bump index only after set. - self->size++; - return _self; -} - -// Used by parsing handlers. -void RepeatedField_push_native(VALUE _self, void* data) { - RepeatedField* self = ruby_to_RepeatedField(_self); - upb_fieldtype_t field_type = self->field_type; - int element_size = native_slot_size(field_type); - RepeatedField_reserve(self, self->size + 1); - int index = self->size; - void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); - memcpy(memory, data, element_size); - self->size++; -} - -void* RepeatedField_index_native(VALUE _self, int index) { - RepeatedField* self = ruby_to_RepeatedField(_self); - upb_fieldtype_t field_type = self->field_type; - int element_size = native_slot_size(field_type); - return ((uint8_t *)self->elements) + index * element_size; -} - -/* - * call-seq: - * RepeatedField.pop => value - * - * Removes the last element and returns it. Throws an exception if the repeated - * field is empty. - */ -VALUE RepeatedField_pop(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - upb_fieldtype_t field_type = self->field_type; - VALUE field_type_class = self->field_type_class; - int element_size = native_slot_size(field_type); - if (self->size == 0) { - rb_raise(rb_eRangeError, "Pop from empty repeated field is not allowed."); - } - int index = self->size - 1; - void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); - VALUE ret = native_slot_get(field_type, field_type_class, memory); - self->size--; - return ret; -} - -/* - * call-seq: - * RepeatedField.insert(*args) - * - * Pushes each arg in turn onto the end of the repeated field. - */ -VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self) { - for (int i = 0; i < argc; i++) { - RepeatedField_push(_self, argv[i]); - } - return Qnil; -} - -/* - * call-seq: - * RepeatedField.replace(list) - * - * Replaces the contents of the repeated field with the given list of elements. - */ -VALUE RepeatedField_replace(VALUE _self, VALUE list) { - RepeatedField* self = ruby_to_RepeatedField(_self); - Check_Type(list, T_ARRAY); - self->size = 0; - for (int i = 0; i < RARRAY_LEN(list); i++) { - RepeatedField_push(_self, rb_ary_entry(list, i)); - } - return Qnil; -} - -/* - * call-seq: - * RepeatedField.clear - * - * Clears (removes all elements from) this repeated field. - */ -VALUE RepeatedField_clear(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - self->size = 0; - return Qnil; -} - -/* - * call-seq: - * RepeatedField.length - * - * Returns the length of this repeated field. - */ -VALUE RepeatedField_length(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - return INT2NUM(self->size); -} - -static VALUE RepeatedField_new_this_type(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - VALUE new_rptfield = Qnil; - VALUE element_type = fieldtype_to_ruby(self->field_type); - if (self->field_type_class != Qnil) { - new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2, - element_type, self->field_type_class); - } else { - new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 1, - element_type); - } - return new_rptfield; -} - -/* - * call-seq: - * RepeatedField.dup => repeated_field - * - * Duplicates this repeated field with a shallow copy. References to all - * non-primitive element objects (e.g., submessages) are shared. - */ -VALUE RepeatedField_dup(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - VALUE new_rptfield = RepeatedField_new_this_type(_self); - RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield); - RepeatedField_reserve(new_rptfield_self, self->size); - upb_fieldtype_t field_type = self->field_type; - size_t elem_size = native_slot_size(field_type); - size_t off = 0; - for (int i = 0; i < self->size; i++, off += elem_size) { - void* to_mem = (uint8_t *)new_rptfield_self->elements + off; - void* from_mem = (uint8_t *)self->elements + off; - native_slot_dup(field_type, to_mem, from_mem); - new_rptfield_self->size++; - } - - return new_rptfield; -} - -// Internal only: used by Google::Protobuf.deep_copy. -VALUE RepeatedField_deep_copy(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - VALUE new_rptfield = RepeatedField_new_this_type(_self); - RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield); - RepeatedField_reserve(new_rptfield_self, self->size); - upb_fieldtype_t field_type = self->field_type; - size_t elem_size = native_slot_size(field_type); - size_t off = 0; - for (int i = 0; i < self->size; i++, off += elem_size) { - void* to_mem = (uint8_t *)new_rptfield_self->elements + off; - void* from_mem = (uint8_t *)self->elements + off; - native_slot_deep_copy(field_type, to_mem, from_mem); - new_rptfield_self->size++; - } - - return new_rptfield; -} - -/* - * call-seq: - * RepeatedField.==(other) => boolean - * - * Compares this repeated field to another. Repeated fields are equal if their - * element types are equal, their lengths are equal, and each element is equal. - * Elements are compared as per normal Ruby semantics, by calling their :== - * methods (or performing a more efficient comparison for primitive types). - */ -VALUE RepeatedField_eq(VALUE _self, VALUE _other) { - if (_self == _other) { - return Qtrue; - } - RepeatedField* self = ruby_to_RepeatedField(_self); - - // Inefficient but workable: to support comparison to a generic array, we - // build a temporary RepeatedField of our type. - if (TYPE(_other) == T_ARRAY) { - VALUE new_rptfield = RepeatedField_new_this_type(_self); - for (int i = 0; i < RARRAY_LEN(_other); i++) { - VALUE elem = rb_ary_entry(_other, i); - RepeatedField_push(new_rptfield, elem); - } - _other = new_rptfield; - } - - RepeatedField* other = ruby_to_RepeatedField(_other); - if (self->field_type != other->field_type || - self->field_type_class != other->field_type_class || - self->size != other->size) { - return Qfalse; - } - - upb_fieldtype_t field_type = self->field_type; - size_t elem_size = native_slot_size(field_type); - size_t off = 0; - for (int i = 0; i < self->size; i++, off += elem_size) { - void* self_mem = ((uint8_t *)self->elements) + off; - void* other_mem = ((uint8_t *)other->elements) + off; - if (!native_slot_eq(field_type, self_mem, other_mem)) { - return Qfalse; - } - } - return Qtrue; -} - -/* - * call-seq: - * RepeatedField.hash => hash_value - * - * Returns a hash value computed from this repeated field's elements. - */ -VALUE RepeatedField_hash(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - - VALUE hash = LL2NUM(0); - - upb_fieldtype_t field_type = self->field_type; - VALUE field_type_class = self->field_type_class; - size_t elem_size = native_slot_size(field_type); - size_t off = 0; - for (int i = 0; i < self->size; i++, off += elem_size) { - void* mem = ((uint8_t *)self->elements) + off; - VALUE elem = native_slot_get(field_type, field_type_class, mem); - hash = rb_funcall(hash, rb_intern("<<"), 1, INT2NUM(2)); - hash = rb_funcall(hash, rb_intern("^"), 1, - rb_funcall(elem, rb_intern("hash"), 0)); - } - - return hash; -} - -/* - * call-seq: - * RepeatedField.inspect => string - * - * Returns a string representing this repeated field's elements. It will be - * formated as "[<element>, <element>, ...]", with each element's string - * representation computed by its own #inspect method. - */ -VALUE RepeatedField_inspect(VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - - VALUE str = rb_str_new2("["); - - bool first = true; - - upb_fieldtype_t field_type = self->field_type; - VALUE field_type_class = self->field_type_class; - size_t elem_size = native_slot_size(field_type); - size_t off = 0; - for (int i = 0; i < self->size; i++, off += elem_size) { - void* mem = ((uint8_t *)self->elements) + off; - VALUE elem = native_slot_get(field_type, field_type_class, mem); - if (!first) { - str = rb_str_cat2(str, ", "); - } else { - first = false; - } - str = rb_str_append(str, rb_funcall(elem, rb_intern("inspect"), 0)); - } - - str = rb_str_cat2(str, "]"); - return str; -} - -/* - * call-seq: - * RepeatedField.+(other) => repeated field - * - * Returns a new repeated field that contains the concatenated list of this - * repeated field's elements and other's elements. The other (second) list may - * be either another repeated field or a Ruby array. - */ -VALUE RepeatedField_plus(VALUE _self, VALUE list) { - VALUE dupped = RepeatedField_dup(_self); - - if (TYPE(list) == T_ARRAY) { - for (int i = 0; i < RARRAY_LEN(list); i++) { - VALUE elem = rb_ary_entry(list, i); - RepeatedField_push(dupped, elem); - } - } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) && - RTYPEDDATA_TYPE(list) == &RepeatedField_type) { - RepeatedField* self = ruby_to_RepeatedField(_self); - RepeatedField* list_rptfield = ruby_to_RepeatedField(list); - if (self->field_type != list_rptfield->field_type || - self->field_type_class != list_rptfield->field_type_class) { - rb_raise(rb_eArgError, - "Attempt to append RepeatedField with different element type."); - } - for (int i = 0; i < list_rptfield->size; i++) { - void* mem = RepeatedField_index_native(list, i); - RepeatedField_push_native(dupped, mem); - } - } else { - rb_raise(rb_eArgError, "Unknown type appending to RepeatedField"); - } - - return dupped; -} - -static void validate_type_class(upb_fieldtype_t type, VALUE klass) { - if (rb_iv_get(klass, kDescriptorInstanceVar) == Qnil) { - rb_raise(rb_eArgError, - "Type class has no descriptor. Please pass a " - "class or enum as returned by the DescriptorPool."); - } - if (type == UPB_TYPE_MESSAGE) { - VALUE desc = rb_iv_get(klass, kDescriptorInstanceVar); - if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) || - RTYPEDDATA_TYPE(desc) != &_Descriptor_type) { - rb_raise(rb_eArgError, "Descriptor has an incorrect type."); - } - if (rb_get_alloc_func(klass) != &Message_alloc) { - rb_raise(rb_eArgError, - "Message class was not returned by the DescriptorPool."); - } - } else if (type == UPB_TYPE_ENUM) { - VALUE enumdesc = rb_iv_get(klass, kDescriptorInstanceVar); - if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) || - RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) { - rb_raise(rb_eArgError, "Descriptor has an incorrect type."); - } - } -} - -void RepeatedField_init_args(int argc, VALUE* argv, - VALUE _self) { - RepeatedField* self = ruby_to_RepeatedField(_self); - VALUE ary = Qnil; - if (argc < 1) { - rb_raise(rb_eArgError, "Expected at least 1 argument."); - } - self->field_type = ruby_to_fieldtype(argv[0]); - - if (self->field_type == UPB_TYPE_MESSAGE || - self->field_type == UPB_TYPE_ENUM) { - if (argc < 2) { - rb_raise(rb_eArgError, "Expected at least 2 arguments for message/enum."); - } - self->field_type_class = argv[1]; - if (argc > 2) { - ary = argv[2]; - } - validate_type_class(self->field_type, self->field_type_class); - } else { - if (argc > 2) { - rb_raise(rb_eArgError, "Too many arguments: expected 1 or 2."); - } - if (argc > 1) { - ary = argv[1]; - } - } - - if (ary != Qnil) { - if (!RB_TYPE_P(ary, T_ARRAY)) { - rb_raise(rb_eArgError, "Expected array as initialize argument"); - } - for (int i = 0; i < RARRAY_LEN(ary); i++) { - RepeatedField_push(_self, rb_ary_entry(ary, i)); - } - } -} - -// Mark, free, alloc, init and class setup functions. - -void RepeatedField_mark(void* _self) { - RepeatedField* self = (RepeatedField*)_self; - rb_gc_mark(self->field_type_class); - upb_fieldtype_t field_type = self->field_type; - int element_size = native_slot_size(field_type); - for (int i = 0; i < self->size; i++) { - void* memory = (((uint8_t *)self->elements) + i * element_size); - native_slot_mark(self->field_type, memory); - } -} - -void RepeatedField_free(void* _self) { - RepeatedField* self = (RepeatedField*)_self; - xfree(self->elements); - xfree(self); -} - -/* - * call-seq: - * RepeatedField.new(type, type_class = nil, initial_elems = []) - * - * Creates a new repeated field. The provided type must be a Ruby symbol, and - * can take on the same values as those accepted by FieldDescriptor#type=. If - * the type is :message or :enum, type_class must be non-nil, and must be the - * Ruby class or module returned by Descriptor#msgclass or - * EnumDescriptor#enummodule, respectively. An initial list of elements may also - * be provided. - */ -VALUE RepeatedField_alloc(VALUE klass) { - RepeatedField* self = ALLOC(RepeatedField); - self->elements = NULL; - self->size = 0; - self->capacity = 0; - self->field_type = -1; - self->field_type_class = Qnil; - VALUE ret = TypedData_Wrap_Struct(klass, &RepeatedField_type, self); - return ret; -} - -VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) { - RepeatedField_init_args(argc, argv, self); - return Qnil; -} - -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); - - rb_define_method(klass, "initialize", - RepeatedField_init, -1); - rb_define_method(klass, "each", RepeatedField_each, 0); - rb_define_method(klass, "[]", RepeatedField_index, 1); - rb_define_method(klass, "[]=", RepeatedField_index_set, 2); - rb_define_method(klass, "push", RepeatedField_push, 1); - rb_define_method(klass, "<<", RepeatedField_push, 1); - rb_define_method(klass, "pop", RepeatedField_pop, 0); - rb_define_method(klass, "insert", RepeatedField_insert, -1); - rb_define_method(klass, "replace", RepeatedField_replace, 1); - rb_define_method(klass, "clear", RepeatedField_clear, 0); - rb_define_method(klass, "length", RepeatedField_length, 0); - rb_define_method(klass, "dup", RepeatedField_dup, 0); - // Also define #clone so that we don't inherit Object#clone. - rb_define_method(klass, "clone", RepeatedField_dup, 0); - rb_define_method(klass, "==", RepeatedField_eq, 1); - rb_define_method(klass, "hash", RepeatedField_hash, 0); - rb_define_method(klass, "inspect", RepeatedField_inspect, 0); - rb_define_method(klass, "+", RepeatedField_plus, 1); - rb_include_module(klass, rb_mEnumerable); -} diff --git a/ruby/ext/protobuf_c/storage.c b/ruby/ext/protobuf_c/storage.c deleted file mode 100644 index c4d801af..00000000 --- a/ruby/ext/protobuf_c/storage.c +++ /dev/null @@ -1,577 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -#include <math.h> - -#include <ruby/encoding.h> - -// ----------------------------------------------------------------------------- -// Ruby <-> native slot management. -// ----------------------------------------------------------------------------- - -#define DEREF(memory, type) *(type*)(memory) - -size_t native_slot_size(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_FLOAT: return 4; - case UPB_TYPE_DOUBLE: return 8; - case UPB_TYPE_BOOL: return 1; - case UPB_TYPE_STRING: return sizeof(VALUE); - case UPB_TYPE_BYTES: return sizeof(VALUE); - case UPB_TYPE_MESSAGE: return sizeof(VALUE); - case UPB_TYPE_ENUM: return 4; - case UPB_TYPE_INT32: return 4; - case UPB_TYPE_INT64: return 8; - case UPB_TYPE_UINT32: return 4; - case UPB_TYPE_UINT64: return 8; - default: return 0; - } -} - -static void check_int_range_precision(upb_fieldtype_t type, VALUE val) { - // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper - // bound; we just need to do precision checks (i.e., disallow rounding) and - // check for < 0 on unsigned types. - if (TYPE(val) == T_FLOAT) { - double dbl_val = NUM2DBL(val); - if (floor(dbl_val) != dbl_val) { - rb_raise(rb_eRangeError, - "Non-integral floating point value assigned to integer field."); - } - } - if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) { - if (NUM2DBL(val) < 0) { - rb_raise(rb_eRangeError, - "Assigning negative value to unsigned integer field."); - } - } -} - -static bool is_ruby_num(VALUE value) { - return (TYPE(value) == T_FLOAT || - TYPE(value) == T_FIXNUM || - TYPE(value) == T_BIGNUM); -} - -void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) { - bool bad_encoding = false; - rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value)); - if (type == UPB_TYPE_STRING) { - bad_encoding = - string_encoding != kRubyStringUtf8Encoding && - string_encoding != kRubyStringASCIIEncoding; - } else { - bad_encoding = - string_encoding != kRubyString8bitEncoding; - } - // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT - // (for bytes fields). - if (bad_encoding) { - rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)", - (type == UPB_TYPE_STRING) ? "string" : "bytes", - (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT", - rb_enc_name(string_encoding)); - } -} - -void native_slot_set(upb_fieldtype_t type, VALUE type_class, - void* memory, VALUE value) { - switch (type) { - case UPB_TYPE_FLOAT: - if (!is_ruby_num(value)) { - rb_raise(rb_eTypeError, "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."); - } - DEREF(memory, double) = NUM2DBL(value); - break; - case UPB_TYPE_BOOL: { - int8_t val = -1; - if (value == Qtrue) { - val = 1; - } else if (value == Qfalse) { - val = 0; - } else { - rb_raise(rb_eTypeError, "Invalid argument for boolean field."); - } - DEREF(memory, int8_t) = val; - break; - } - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if (CLASS_OF(value) != rb_cString) { - rb_raise(rb_eTypeError, "Invalid argument for string field."); - } - native_slot_validate_string_encoding(type, value); - DEREF(memory, VALUE) = value; - break; - } - case UPB_TYPE_MESSAGE: { - if (CLASS_OF(value) != type_class) { - rb_raise(rb_eTypeError, - "Invalid type %s to assign to submessage field.", - rb_class2name(CLASS_OF(value))); - } - DEREF(memory, VALUE) = value; - break; - } - case UPB_TYPE_ENUM: { - if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) { - rb_raise(rb_eTypeError, - "Expected number or symbol type for enum field."); - } - int32_t int_val = 0; - if (TYPE(value) == T_SYMBOL) { - // Ensure that the given symbol exists in the enum module. - VALUE lookup = rb_const_get(type_class, SYM2ID(value)); - if (lookup == Qnil) { - rb_raise(rb_eRangeError, "Unknown symbol value for enum field."); - } else { - int_val = NUM2INT(lookup); - } - } else { - check_int_range_precision(UPB_TYPE_INT32, value); - int_val = NUM2INT(value); - } - DEREF(memory, int32_t) = int_val; - break; - } - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - if (!is_ruby_num(value)) { - rb_raise(rb_eTypeError, "Expected number type for integral field."); - } - check_int_range_precision(type, value); - switch (type) { - case UPB_TYPE_INT32: - DEREF(memory, int32_t) = NUM2INT(value); - break; - case UPB_TYPE_INT64: - DEREF(memory, int64_t) = NUM2LL(value); - break; - case UPB_TYPE_UINT32: - DEREF(memory, uint32_t) = NUM2UINT(value); - break; - case UPB_TYPE_UINT64: - DEREF(memory, uint64_t) = NUM2ULL(value); - break; - default: - break; - } - break; - default: - break; - } -} - -VALUE native_slot_get(upb_fieldtype_t type, VALUE type_class, void* memory) { - switch (type) { - case UPB_TYPE_FLOAT: - return DBL2NUM(DEREF(memory, float)); - case UPB_TYPE_DOUBLE: - return DBL2NUM(DEREF(memory, double)); - case UPB_TYPE_BOOL: - return DEREF(memory, int8_t) ? Qtrue : Qfalse; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - return *((VALUE *)memory); - case UPB_TYPE_ENUM: { - int32_t val = DEREF(memory, int32_t); - VALUE symbol = enum_lookup(type_class, INT2NUM(val)); - if (symbol == Qnil) { - return INT2NUM(val); - } else { - return symbol; - } - } - case UPB_TYPE_INT32: - return INT2NUM(DEREF(memory, int32_t)); - case UPB_TYPE_INT64: - return LL2NUM(DEREF(memory, int64_t)); - case UPB_TYPE_UINT32: - return UINT2NUM(DEREF(memory, uint32_t)); - case UPB_TYPE_UINT64: - return ULL2NUM(DEREF(memory, uint64_t)); - default: - return Qnil; - } -} - -void native_slot_init(upb_fieldtype_t type, void* memory) { - switch (type) { - case UPB_TYPE_FLOAT: - DEREF(memory, float) = 0.0; - break; - case UPB_TYPE_DOUBLE: - DEREF(memory, double) = 0.0; - break; - case UPB_TYPE_BOOL: - DEREF(memory, int8_t) = 0; - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - // TODO(cfallin): set encoding appropriately - DEREF(memory, VALUE) = rb_str_new2(""); - break; - case UPB_TYPE_MESSAGE: - DEREF(memory, VALUE) = Qnil; - break; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - DEREF(memory, int32_t) = 0; - break; - case UPB_TYPE_INT64: - DEREF(memory, int64_t) = 0; - break; - case UPB_TYPE_UINT32: - DEREF(memory, uint32_t) = 0; - break; - case UPB_TYPE_UINT64: - DEREF(memory, uint64_t) = 0; - break; - default: - break; - } -} - -void native_slot_mark(upb_fieldtype_t type, void* memory) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - rb_gc_mark(DEREF(memory, VALUE)); - break; - default: - break; - } -} - -void native_slot_dup(upb_fieldtype_t type, void* to, void* from) { - memcpy(to, from, native_slot_size(type)); -} - -void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - VALUE from_val = DEREF(from, VALUE); - DEREF(to, VALUE) = (from_val != Qnil) ? - rb_funcall(from_val, rb_intern("dup"), 0) : Qnil; - break; - } - case UPB_TYPE_MESSAGE: { - VALUE from_val = DEREF(from, VALUE); - DEREF(to, VALUE) = (from_val != Qnil) ? - Message_deep_copy(from_val) : Qnil; - break; - } - default: - memcpy(to, from, native_slot_size(type)); - } -} - -bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: { - VALUE val1 = DEREF(mem1, VALUE); - VALUE val2 = DEREF(mem2, VALUE); - VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2); - return ret == Qtrue; - } - default: - return !memcmp(mem1, mem2, native_slot_size(type)); - } -} - -// ----------------------------------------------------------------------------- -// Memory layout management. -// ----------------------------------------------------------------------------- - -MessageLayout* create_layout(const upb_msgdef* msgdef) { - MessageLayout* layout = ALLOC(MessageLayout); - int nfields = upb_msgdef_numfields(msgdef); - layout->offsets = ALLOC_N(size_t, nfields); - - upb_msg_iter it; - size_t off = 0; - for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - size_t field_size = - (upb_fielddef_label(field) == UPB_LABEL_REPEATED) ? - sizeof(VALUE) : native_slot_size(upb_fielddef_type(field)); - // align current offset - off = (off + field_size - 1) & ~(field_size - 1); - layout->offsets[upb_fielddef_index(field)] = off; - off += field_size; - } - - layout->size = off; - - layout->msgdef = msgdef; - upb_msgdef_ref(layout->msgdef, &layout->msgdef); - - return layout; -} - -void free_layout(MessageLayout* layout) { - xfree(layout->offsets); - upb_msgdef_unref(layout->msgdef, &layout->msgdef); - xfree(layout); -} - -static VALUE get_type_class(const upb_fielddef* field) { - VALUE type_class = Qnil; - if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { - VALUE submsgdesc = - get_def_obj(upb_fielddef_subdef(field)); - type_class = Descriptor_msgclass(submsgdesc); - } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { - VALUE subenumdesc = - get_def_obj(upb_fielddef_subdef(field)); - type_class = EnumDescriptor_enummodule(subenumdesc); - } - return type_class; -} - -VALUE layout_get(MessageLayout* layout, - void* storage, - const upb_fielddef* field) { - void* memory = ((uint8_t *)storage) + - layout->offsets[upb_fielddef_index(field)]; - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - return *((VALUE *)memory); - } else { - return native_slot_get(upb_fielddef_type(field), - get_type_class(field), - memory); - } -} - -static void check_repeated_field_type(VALUE val, const upb_fielddef* field) { - assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED); - - if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || - RTYPEDDATA_TYPE(val) != &RepeatedField_type) { - rb_raise(rb_eTypeError, "Expected repeated field array"); - } - - RepeatedField* self = ruby_to_RepeatedField(val); - if (self->field_type != upb_fielddef_type(field)) { - rb_raise(rb_eTypeError, "Repeated field array has wrong element type"); - } - - if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE || - upb_fielddef_type(field) == UPB_TYPE_ENUM) { - RepeatedField* self = ruby_to_RepeatedField(val); - if (self->field_type_class != - get_def_obj(upb_fielddef_subdef(field))) { - rb_raise(rb_eTypeError, - "Repeated field array has wrong message/enum class"); - } - } -} - -void layout_set(MessageLayout* layout, - void* storage, - const upb_fielddef* field, - VALUE val) { - void* memory = ((uint8_t *)storage) + - layout->offsets[upb_fielddef_index(field)]; - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - check_repeated_field_type(val, field); - *((VALUE *)memory) = val; - } else { - native_slot_set(upb_fielddef_type(field), get_type_class(field), - memory, val); - } -} - -void layout_init(MessageLayout* layout, - void* storage) { - upb_msg_iter it; - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* memory = ((uint8_t *)storage) + - layout->offsets[upb_fielddef_index(field)]; - - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - VALUE ary = Qnil; - VALUE type_class = get_type_class(field); - if (type_class != Qnil) { - VALUE args[2] = { - fieldtype_to_ruby(upb_fielddef_type(field)), - type_class, - }; - ary = rb_class_new_instance(2, args, cRepeatedField); - } else { - VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) }; - ary = rb_class_new_instance(1, args, cRepeatedField); - } - *((VALUE *)memory) = ary; - } else { - native_slot_init(upb_fielddef_type(field), memory); - } - } -} - -void layout_mark(MessageLayout* layout, void* storage) { - upb_msg_iter it; - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* memory = ((uint8_t *)storage) + - layout->offsets[upb_fielddef_index(field)]; - - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - rb_gc_mark(*((VALUE *)memory)); - } else { - native_slot_mark(upb_fielddef_type(field), memory); - } - } -} - -void layout_dup(MessageLayout* layout, void* to, void* from) { - upb_msg_iter it; - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* to_memory = ((uint8_t *)to) + - layout->offsets[upb_fielddef_index(field)]; - void* from_memory = ((uint8_t *)from) + - layout->offsets[upb_fielddef_index(field)]; - - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - *((VALUE *)to_memory) = RepeatedField_dup(*((VALUE *)from_memory)); - } else { - native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); - } - } -} - -void layout_deep_copy(MessageLayout* layout, void* to, void* from) { - upb_msg_iter it; - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* to_memory = ((uint8_t *)to) + - layout->offsets[upb_fielddef_index(field)]; - void* from_memory = ((uint8_t *)from) + - layout->offsets[upb_fielddef_index(field)]; - - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - *((VALUE *)to_memory) = RepeatedField_deep_copy(*((VALUE *)from_memory)); - } else { - native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); - } - } -} - -VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) { - upb_msg_iter it; - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* msg1_memory = ((uint8_t *)msg1) + - layout->offsets[upb_fielddef_index(field)]; - void* msg2_memory = ((uint8_t *)msg2) + - layout->offsets[upb_fielddef_index(field)]; - - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - if (RepeatedField_eq(*((VALUE *)msg1_memory), - *((VALUE *)msg2_memory)) == Qfalse) { - return Qfalse; - } - } else { - if (!native_slot_eq(upb_fielddef_type(field), - msg1_memory, msg2_memory)) { - return Qfalse; - } - } - } - return Qtrue; -} - -VALUE layout_hash(MessageLayout* layout, void* storage) { - upb_msg_iter it; - st_index_t h = rb_hash_start(0); - VALUE hash_sym = rb_intern("hash"); - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - VALUE field_val = layout_get(layout, storage, field); - h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0))); - } - h = rb_hash_end(h); - - return INT2FIX(h); -} - -VALUE layout_inspect(MessageLayout* layout, void* storage) { - VALUE str = rb_str_new2(""); - - upb_msg_iter it; - bool first = true; - for (upb_msg_begin(&it, layout->msgdef); - !upb_msg_done(&it); - upb_msg_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - VALUE field_val = layout_get(layout, storage, field); - - if (!first) { - str = rb_str_cat2(str, ", "); - } else { - first = false; - } - str = rb_str_cat2(str, upb_fielddef_name(field)); - str = rb_str_cat2(str, ": "); - - str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0)); - } - - return str; -} |