浏览代码

Revert "Updated upb from defcleanup branch and modified Ruby to use it (#5539)" (#5848)

This reverts commit 37581380fbc2a2b683e16de01db628988b72541e.
Joshua Haberman 6 年之前
父节点
当前提交
1568deab40

文件差异内容过多而无法显示
+ 346 - 408
ruby/ext/google/protobuf_c/defs.c


+ 226 - 153
ruby/ext/google/protobuf_c/encode_decode.c

@@ -117,18 +117,18 @@ static const void* newhandlerdata(upb_handlers* h, uint32_t ofs, int32_t hasbit)
 typedef struct {
   size_t ofs;
   int32_t hasbit;
-  VALUE subklass;
+  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,
                                         int32_t hasbit,
-                                        VALUE subklass) {
+                                        const upb_fielddef* f) {
   submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
   hd->ofs = ofs;
   hd->hasbit = hasbit;
-  hd->subklass = subklass;
+  hd->md = upb_fielddef_msgsubdef(f);
   upb_handlers_addcleanup(h, hd, xfree);
   return hd;
 }
@@ -137,14 +137,13 @@ typedef struct {
   size_t ofs;              // union data slot
   size_t case_ofs;         // oneof_case field
   uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
-  VALUE subklass;
+  const upb_msgdef *md;    // msgdef, for oneof submessage handler
 } oneof_handlerdata_t;
 
 static const void *newoneofhandlerdata(upb_handlers *h,
                                        uint32_t ofs,
                                        uint32_t case_ofs,
-                                       const upb_fielddef *f,
-                                       const Descriptor* desc) {
+                                       const upb_fielddef *f) {
   oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
   hd->ofs = ofs;
   hd->case_ofs = case_ofs;
@@ -155,7 +154,11 @@ static const void *newoneofhandlerdata(upb_handlers *h,
   // create a separate ID space. In addition, using the field tag number here
   // lets us easily look up the field in the oneof accessor.
   hd->oneof_case_num = upb_fielddef_number(f);
-  hd->subklass = field_type_class(desc->layout, f);
+  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
+    hd->md = upb_fielddef_msgsubdef(f);
+  } else {
+    hd->md = NULL;
+  }
   upb_handlers_addcleanup(h, hd, xfree);
   return hd;
 }
@@ -251,13 +254,13 @@ static size_t stringdata_handler(void* closure, const void* hd,
 }
 
 static bool stringdata_end_handler(void* closure, const void* hd) {
-  VALUE rb_str = (VALUE)closure;
+  VALUE rb_str = closure;
   rb_obj_freeze(rb_str);
   return true;
 }
 
 static bool appendstring_end_handler(void* closure, const void* hd) {
-  VALUE rb_str = (VALUE)closure;
+  VALUE rb_str = closure;
   rb_obj_freeze(rb_str);
   return true;
 }
@@ -266,9 +269,12 @@ static bool appendstring_end_handler(void* closure, const void* hd) {
 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);
   MessageHeader* submsg;
 
-  VALUE submsg_rb = rb_class_new_instance(0, NULL, submsgdata->subklass);
+  VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass);
   RepeatedField_push(ary, submsg_rb);
 
   TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
@@ -279,12 +285,15 @@ static void *appendsubmsg_handler(void *closure, const void *hd) {
 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);
   VALUE submsg_rb;
   MessageHeader* submsg;
 
   if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
     DEREF(msg, submsgdata->ofs, VALUE) =
-        rb_class_new_instance(0, NULL, submsgdata->subklass);
+        rb_class_new_instance(0, NULL, subklass);
   }
 
   set_hasbit(closure, submsgdata->hasbit);
@@ -300,7 +309,11 @@ typedef struct {
   size_t ofs;
   upb_fieldtype_t key_field_type;
   upb_fieldtype_t value_field_type;
-  VALUE subklass;
+
+  // We know that we can hold this reference because the handlerdata has the
+  // same lifetime as the upb_handlers struct, and the upb_handlers struct holds
+  // a reference to the upb_msgdef, which in turn has references to its subdefs.
+  const upb_def* value_field_subdef;
 } map_handlerdata_t;
 
 // Temporary frame for map parsing: at the beginning of a map entry message, a
@@ -375,7 +388,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
 
   if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
       mapdata->value_field_type == UPB_TYPE_ENUM) {
-    value_field_typeclass = mapdata->subklass;
+    value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
   }
 
   value = native_slot_get(
@@ -398,7 +411,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
 static map_handlerdata_t* new_map_handlerdata(
     size_t ofs,
     const upb_msgdef* mapentry_def,
-    const Descriptor* desc) {
+    Descriptor* desc) {
   const upb_fielddef* key_field;
   const upb_fielddef* value_field;
   map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
@@ -409,7 +422,7 @@ static map_handlerdata_t* new_map_handlerdata(
   value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
   assert(value_field != NULL);
   hd->value_field_type = upb_fielddef_type(value_field);
-  hd->subklass = field_type_class(desc->layout, value_field);
+  hd->value_field_subdef = upb_fielddef_subdef(value_field);
 
   return hd;
 }
@@ -475,13 +488,16 @@ static void *oneofsubmsg_handler(void *closure,
   const oneof_handlerdata_t *oneofdata = hd;
   uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
 
+  VALUE subdesc =
+      get_def_obj((void*)oneofdata->md);
+  VALUE subklass = Descriptor_msgclass(subdesc);
   VALUE submsg_rb;
   MessageHeader* submsg;
 
   if (oldcase != oneofdata->oneof_case_num ||
       DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
     DEREF(msg, oneofdata->ofs, VALUE) =
-        rb_class_new_instance(0, NULL, oneofdata->subklass);
+        rb_class_new_instance(0, NULL, subklass);
   }
   // Set the oneof case *after* allocating the new class instance -- otherwise,
   // if the Ruby GC is invoked as part of a call into the VM, it might invoke
@@ -499,12 +515,12 @@ static void *oneofsubmsg_handler(void *closure,
 
 // Set up handlers for a repeated field.
 static void add_handlers_for_repeated_field(upb_handlers *h,
-                                            const Descriptor* desc,
                                             const upb_fielddef *f,
                                             size_t offset) {
-  upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-  attr.handler_data = newhandlerdata(h, offset, -1);
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset, -1));
   upb_handlers_setstartseq(h, f, startseq_handler, &attr);
+  upb_handlerattr_uninit(&attr);
 
   switch (upb_fielddef_type(f)) {
 
@@ -535,20 +551,20 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
       break;
     }
     case UPB_TYPE_MESSAGE: {
-      VALUE subklass = field_type_class(desc->layout, f);
-      upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-      attr.handler_data = newsubmsghandlerdata(h, 0, -1, subklass);
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, -1, f));
       upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
+      upb_handlerattr_uninit(&attr);
       break;
     }
   }
 }
 
 // Set up handlers for a singular field.
-static void add_handlers_for_singular_field(const Descriptor* desc,
-                                            upb_handlers* h,
-                                            const upb_fielddef* f,
-                                            size_t offset, size_t hasbit_off) {
+static void add_handlers_for_singular_field(upb_handlers *h,
+                                            const upb_fielddef *f,
+                                            size_t offset,
+                                            size_t hasbit_off) {
   // The offset we pass to UPB points to the start of the Message,
   // rather than the start of where our data is stored.
   int32_t hasbit = -1;
@@ -570,20 +586,23 @@ static void add_handlers_for_singular_field(const Descriptor* desc,
     case UPB_TYPE_STRING:
     case UPB_TYPE_BYTES: {
       bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
-      upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-      attr.handler_data = newhandlerdata(h, offset, hasbit);
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset, hasbit));
       upb_handlers_setstartstr(h, f,
                                is_bytes ? bytes_handler : str_handler,
                                &attr);
       upb_handlers_setstring(h, f, stringdata_handler, &attr);
       upb_handlers_setendstr(h, f, stringdata_end_handler, &attr);
+      upb_handlerattr_uninit(&attr);
       break;
     }
     case UPB_TYPE_MESSAGE: {
-      upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-      attr.handler_data = newsubmsghandlerdata(
-          h, offset, hasbit, field_type_class(desc->layout, f));
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr,
+				     newsubmsghandlerdata(h, offset,
+							  hasbit, f));
       upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
+      upb_handlerattr_uninit(&attr);
       break;
     }
   }
@@ -593,34 +612,36 @@ static void add_handlers_for_singular_field(const Descriptor* desc,
 static void add_handlers_for_mapfield(upb_handlers* h,
                                       const upb_fielddef* fielddef,
                                       size_t offset,
-                                      const Descriptor* desc) {
+                                      Descriptor* desc) {
   const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
   map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
-  upb_handlerattr attr = UPB_HANDLERATTR_INIT;
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
 
   upb_handlers_addcleanup(h, hd, xfree);
-  attr.handler_data = hd;
+  upb_handlerattr_sethandlerdata(&attr, hd);
   upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
+  upb_handlerattr_uninit(&attr);
 }
 
 // Adds handlers to a map-entry msgdef.
-static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
-                                      const Descriptor* desc) {
+static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
+                                      upb_handlers* h,
+                                      Descriptor* desc) {
   const upb_fielddef* key_field = map_entry_key(msgdef);
   const upb_fielddef* value_field = map_entry_value(msgdef);
   map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
-  upb_handlerattr attr = UPB_HANDLERATTR_INIT;
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
 
   upb_handlers_addcleanup(h, hd, xfree);
-  attr.handler_data = hd;
+  upb_handlerattr_sethandlerdata(&attr, hd);
   upb_handlers_setendmsg(h, endmap_handler, &attr);
 
   add_handlers_for_singular_field(
-      desc, h, key_field,
+      h, key_field,
       offsetof(map_parse_frame_t, key_storage),
       MESSAGE_FIELD_NO_HASBIT);
   add_handlers_for_singular_field(
-      desc, h, value_field,
+      h, value_field,
       offsetof(map_parse_frame_t, value_storage),
       MESSAGE_FIELD_NO_HASBIT);
 }
@@ -629,11 +650,11 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
 static void add_handlers_for_oneof_field(upb_handlers *h,
                                          const upb_fielddef *f,
                                          size_t offset,
-                                         size_t oneof_case_offset,
-                                         const Descriptor* desc) {
-  upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-  attr.handler_data =
-      newoneofhandlerdata(h, offset, oneof_case_offset, f, desc);
+                                         size_t oneof_case_offset) {
+
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(
+      &attr, newoneofhandlerdata(h, offset, oneof_case_offset, f));
 
   switch (upb_fielddef_type(f)) {
 
@@ -668,6 +689,8 @@ static void add_handlers_for_oneof_field(upb_handlers *h,
       break;
     }
   }
+
+  upb_handlerattr_uninit(&attr);
 }
 
 static bool unknown_field_handler(void* closure, const void* hd,
@@ -685,21 +708,11 @@ static bool unknown_field_handler(void* closure, const void* hd,
   return true;
 }
 
-void add_handlers_for_message(const void *closure, upb_handlers *h) {
-  const VALUE descriptor_pool = (VALUE)closure;
+static void add_handlers_for_message(const void *closure, upb_handlers *h) {
   const upb_msgdef* msgdef = upb_handlers_msgdef(h);
-  Descriptor* desc =
-      ruby_to_Descriptor(get_msgdef_obj(descriptor_pool, msgdef));
+  Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
   upb_msg_field_iter i;
 
-  // 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);
-  }
-
   // If this is a mapentry message type, set up a special set of handlers and
   // bail out of the normal (user-defined) message type handling.
   if (upb_msgdef_mapentry(msgdef)) {
@@ -707,7 +720,15 @@ void add_handlers_for_message(const void *closure, upb_handlers *h) {
     return;
   }
 
-  upb_handlerattr attr = UPB_HANDLERATTR_INIT;
+  // 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_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
   upb_handlers_setunknown(h, unknown_field_handler, &attr);
 
   for (upb_msg_field_begin(&i, desc->msgdef);
@@ -721,51 +742,64 @@ void add_handlers_for_message(const void *closure, upb_handlers *h) {
       size_t oneof_case_offset =
           desc->layout->fields[upb_fielddef_index(f)].case_offset +
           sizeof(MessageHeader);
-      add_handlers_for_oneof_field(h, f, offset, oneof_case_offset, desc);
+      add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
     } else if (is_map_field(f)) {
       add_handlers_for_mapfield(h, f, offset, desc);
     } else if (upb_fielddef_isseq(f)) {
-      add_handlers_for_repeated_field(h, desc, f, offset);
+      add_handlers_for_repeated_field(h, f, offset);
     } else {
       add_handlers_for_singular_field(
-          desc, h, f, offset,
-          desc->layout->fields[upb_fielddef_index(f)].hasbit);
+          h, f, offset, desc->layout->fields[upb_fielddef_index(f)].hasbit);
     }
   }
 }
 
+// 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) {
-  DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
-  return upb_handlercache_get(pool->fill_handler_cache, desc->msgdef);
+  if (!desc->fill_handlers) {
+    desc->fill_handlers =
+        new_fill_handlers(desc, &desc->fill_handlers);
+  }
+  return desc->fill_handlers;
 }
 
-static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
-  DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
-  return upb_pbcodecache_get(pool->fill_method_cache, desc->msgdef);
-}
+// 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);
 
-static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
-  DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
-  return upb_json_codecache_get(pool->json_fill_method_cache, desc->msgdef);
+  return upb_pbdecodermethod_new(&opts, owner);
 }
 
-static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
-  DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
-  return upb_handlercache_get(pool->pb_serialize_handler_cache, desc->msgdef);
+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;
 }
 
-static const upb_handlers* msgdef_json_serialize_handlers(
-    Descriptor* desc, bool preserve_proto_fieldnames) {
-  DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
-  if (preserve_proto_fieldnames) {
-    return upb_handlercache_get(pool->json_serialize_handler_preserve_cache,
-                                desc->msgdef);
-  } else {
-    return upb_handlercache_get(pool->json_serialize_handler_cache,
-                                desc->msgdef);
+static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
+  if (desc->json_fill_method == NULL) {
+    desc->json_fill_method =
+        upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method);
   }
+  return desc->json_fill_method;
 }
 
 
@@ -775,8 +809,7 @@ static const upb_handlers* msgdef_json_serialize_handlers(
 // if any error occurs.
 #define STACK_ENV_STACKBYTES 4096
 typedef struct {
-  upb_arena *arena;
-  upb_status status;
+  upb_env env;
   const char* ruby_error_template;
   char allocbuf[STACK_ENV_STACKBYTES];
 } stackenv;
@@ -784,22 +817,29 @@ typedef struct {
 static void stackenv_init(stackenv* se, const char* errmsg);
 static void stackenv_uninit(stackenv* se);
 
+// Callback invoked by upb if any error occurs during parsing or serialization.
+static bool env_error_func(void* ud, const upb_status* status) {
+  stackenv* se = ud;
+  // Free the env -- rb_raise will longjmp up the stack past the encode/decode
+  // function so it would not otherwise have been freed.
+  stackenv_uninit(se);
+
+  // TODO(haberman): have a way to verify that this is actually a parse error,
+  // instead of just throwing "parse error" unconditionally.
+  rb_raise(cParseError, se->ruby_error_template, upb_status_errmsg(status));
+  // Never reached: rb_raise() always longjmp()s up the stack, past all of our
+  // code, back to Ruby.
+  return false;
+}
+
 static void stackenv_init(stackenv* se, const char* errmsg) {
   se->ruby_error_template = errmsg;
-  se->arena =
-      upb_arena_init(se->allocbuf, sizeof(se->allocbuf), &upb_alloc_global);
-  upb_status_clear(&se->status);
+  upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL);
+  upb_env_seterrorfunc(&se->env, env_error_func, se);
 }
 
 static void stackenv_uninit(stackenv* se) {
-  upb_arena_free(se->arena);
-
-  if (!upb_ok(&se->status)) {
-    // TODO(haberman): have a way to verify that this is actually a parse error,
-    // instead of just throwing "parse error" unconditionally.
-    VALUE errmsg = rb_str_new2(upb_status_errmsg(&se->status));
-    rb_raise(cParseError, se->ruby_error_template, errmsg);
-  }
+  upb_env_uninit(&se->env);
 }
 
 /*
@@ -830,10 +870,10 @@ VALUE Message_decode(VALUE klass, VALUE data) {
     stackenv se;
     upb_sink sink;
     upb_pbdecoder* decoder;
-    stackenv_init(&se, "Error occurred during parsing: %" PRIsVALUE);
+    stackenv_init(&se, "Error occurred during parsing: %s");
 
     upb_sink_reset(&sink, h, msg);
-    decoder = upb_pbdecoder_create(se.arena, method, sink, &se.status);
+    decoder = upb_pbdecoder_create(&se.env, method, &sink);
     upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
                       upb_pbdecoder_input(decoder));
 
@@ -851,9 +891,8 @@ VALUE Message_decode(VALUE klass, VALUE data) {
  * format) under the interpretration given by this message class's definition
  * and returns a message object with the corresponding field values.
  *
- *  @param options [Hash] options for the decoder
- *   ignore_unknown_fields: set true to ignore unknown fields (default is to
- *   raise an error)
+ * @param options [Hash] options for the decoder
+ *   ignore_unknown_fields: set true to ignore unknown fields (default is to raise an error)
  */
 VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
   VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
@@ -881,7 +920,6 @@ VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
   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.
@@ -895,11 +933,11 @@ VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
     upb_sink sink;
     upb_json_parser* parser;
     DescriptorPool* pool = ruby_to_DescriptorPool(generated_pool);
-    stackenv_init(&se, "Error occurred during parsing: %" PRIsVALUE);
+    stackenv_init(&se, "Error occurred during parsing: %s");
 
     upb_sink_reset(&sink, get_fill_handlers(desc), msg);
-    parser = upb_json_parser_create(se.arena, method, pool->symtab, sink,
-                                    &se.status, RTEST(ignore_unknown_fields));
+    parser = upb_json_parser_create(&se.env, method, pool->symtab,
+                                    &sink, ignore_unknown_fields);
     upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
                       upb_json_parser_input(parser));
 
@@ -915,8 +953,9 @@ VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
 
 /* msgvisitor *****************************************************************/
 
-static void putmsg(VALUE msg, const Descriptor* desc, upb_sink sink, int depth,
-                   bool emit_defaults, bool is_json, bool open_msg);
+static void putmsg(VALUE msg, const Descriptor* desc,
+                   upb_sink *sink, int depth, bool emit_defaults,
+                   bool is_json, bool open_msg);
 
 static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
   upb_selector_t ret;
@@ -925,7 +964,7 @@ static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
   return ret;
 }
 
-static void putstr(VALUE str, const upb_fielddef *f, upb_sink sink) {
+static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
   upb_sink subsink;
 
   if (str == Qnil) return;
@@ -942,12 +981,12 @@ static void putstr(VALUE str, const upb_fielddef *f, upb_sink sink) {
 
   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),
+  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,
+static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
                       int depth, bool emit_defaults, bool is_json) {
   upb_sink subsink;
   VALUE descriptor;
@@ -959,12 +998,12 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink sink,
   subdesc = ruby_to_Descriptor(descriptor);
 
   upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
-  putmsg(submsg, subdesc, subsink, depth + 1, emit_defaults, is_json, true);
+  putmsg(submsg, subdesc, &subsink, depth + 1, emit_defaults, is_json, true);
   upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
 }
 
-static void putary(VALUE ary, const upb_fielddef* f, upb_sink sink, int depth,
-                   bool emit_defaults, bool is_json) {
+static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
+                   int depth, bool emit_defaults, bool is_json) {
   upb_sink subsink;
   upb_fieldtype_t type = upb_fielddef_type(f);
   upb_selector_t sel = 0;
@@ -985,9 +1024,9 @@ static void putary(VALUE ary, const upb_fielddef* f, upb_sink sink, int depth,
   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)); \
+#define T(upbtypeconst, upbtype, ctype)                         \
+  case upbtypeconst:                                            \
+    upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory));   \
     break;
 
       T(UPB_TYPE_FLOAT,  float,  float)
@@ -1001,10 +1040,11 @@ static void putary(VALUE ary, const upb_fielddef* f, upb_sink sink, int depth,
 
       case UPB_TYPE_STRING:
       case UPB_TYPE_BYTES:
-        putstr(*((VALUE *)memory), f, subsink);
+        putstr(*((VALUE *)memory), f, &subsink);
         break;
       case UPB_TYPE_MESSAGE:
-        putsubmsg(*((VALUE*)memory), f, subsink, depth, emit_defaults, is_json);
+        putsubmsg(*((VALUE *)memory), f, &subsink, depth,
+                  emit_defaults, is_json);
         break;
 
 #undef T
@@ -1014,8 +1054,12 @@ static void putary(VALUE ary, const upb_fielddef* f, upb_sink sink, int depth,
   upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
 }
 
-static void put_ruby_value(VALUE value, const upb_fielddef* f, VALUE type_class,
-                           int depth, upb_sink sink, bool emit_defaults,
+static void put_ruby_value(VALUE value,
+                           const upb_fielddef *f,
+                           VALUE type_class,
+                           int depth,
+                           upb_sink *sink,
+                           bool emit_defaults,
                            bool is_json) {
   if (depth > ENCODE_MAX_NESTING) {
     rb_raise(rb_eRuntimeError,
@@ -1065,8 +1109,8 @@ static void put_ruby_value(VALUE value, const upb_fielddef* f, VALUE type_class,
   }
 }
 
-static void putmap(VALUE map, const upb_fielddef* f, upb_sink sink, int depth,
-                   bool emit_defaults, bool is_json) {
+static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
+                   int depth, bool emit_defaults, bool is_json) {
   Map* self;
   upb_sink subsink;
   const upb_fielddef* key_field;
@@ -1090,17 +1134,17 @@ static void putmap(VALUE map, const upb_fielddef* f, upb_sink sink, int depth,
     upb_status status;
 
     upb_sink entry_sink;
-    upb_sink_startsubmsg(subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
+    upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
                          &entry_sink);
-    upb_sink_startmsg(entry_sink);
+    upb_sink_startmsg(&entry_sink);
 
-    put_ruby_value(key, key_field, Qnil, depth + 1, entry_sink, emit_defaults,
-                   is_json);
+    put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink,
+                   emit_defaults, is_json);
     put_ruby_value(value, value_field, self->value_type_class, depth + 1,
-                   entry_sink, emit_defaults, is_json);
+                   &entry_sink, emit_defaults, is_json);
 
-    upb_sink_endmsg(entry_sink, &status);
-    upb_sink_endsubmsg(subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+    upb_sink_endmsg(&entry_sink, &status);
+    upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
   }
 
   upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
@@ -1109,8 +1153,8 @@ static void putmap(VALUE map, const upb_fielddef* f, upb_sink sink, int depth,
 static const upb_handlers* msgdef_json_serialize_handlers(
     Descriptor* desc, bool preserve_proto_fieldnames);
 
-static void putjsonany(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
-                       int depth, bool emit_defaults) {
+static void putjsonany(VALUE msg_rb, const Descriptor* desc,
+                       upb_sink* sink, int depth, bool emit_defaults) {
   upb_status status;
   MessageHeader* msg = NULL;
   const upb_fielddef* type_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_TYPE);
@@ -1166,7 +1210,7 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
     value_len = RSTRING_LEN(value_str_rb);
 
     if (value_len > 0) {
-      VALUE payload_desc_rb = get_msgdef_obj(generated_pool, payload_type);
+      VALUE payload_desc_rb = get_def_obj(payload_type);
       Descriptor* payload_desc = ruby_to_Descriptor(payload_desc_rb);
       VALUE payload_class = Descriptor_msgclass(payload_desc_rb);
       upb_sink subsink;
@@ -1184,8 +1228,8 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
 
       subsink.handlers =
           msgdef_json_serialize_handlers(payload_desc, true);
-      subsink.closure = sink.closure;
-      putmsg(payload_msg_rb, payload_desc, subsink, depth, emit_defaults, true,
+      subsink.closure = sink->closure;
+      putmsg(payload_msg_rb, payload_desc, &subsink, depth, emit_defaults, true,
              is_wellknown);
     }
   }
@@ -1193,8 +1237,9 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
   upb_sink_endmsg(sink, &status);
 }
 
-static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
-                   int depth, bool emit_defaults, bool is_json, bool open_msg) {
+static void putmsg(VALUE msg_rb, const Descriptor* desc,
+                   upb_sink *sink, int depth, bool emit_defaults,
+                   bool is_json, bool open_msg) {
   MessageHeader* msg;
   upb_msg_field_iter i;
   upb_status status;
@@ -1277,19 +1322,20 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
     } else {
       upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
 
-#define T(upbtypeconst, upbtype, ctype, default_value)                       \
-  case upbtypeconst: {                                                       \
-    ctype value = DEREF(msg, offset, ctype);                                 \
-    bool is_default = false;                                                 \
-    if (upb_fielddef_haspresence(f)) {                                       \
-      is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse; \
-    } else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) {       \
-      is_default = default_value == value;                                   \
-    }                                                                        \
-    if (is_matching_oneof || emit_defaults || !is_default) {                 \
-      upb_sink_put##upbtype(sink, sel, value);                               \
-    }                                                                        \
-  } break;
+#define T(upbtypeconst, upbtype, ctype, default_value)                          \
+  case upbtypeconst: {                                                          \
+      ctype value = DEREF(msg, offset, ctype);                                  \
+      bool is_default = false;                                                  \
+      if (upb_fielddef_haspresence(f)) {                                        \
+        is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse;  \
+      } else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) {        \
+        is_default = default_value == value;                                    \
+      }                                                                         \
+      if (is_matching_oneof || emit_defaults || !is_default) {                  \
+        upb_sink_put##upbtype(sink, sel, value);                                \
+      }                                                                         \
+    }                                                                           \
+    break;
 
       switch (upb_fielddef_type(f)) {
         T(UPB_TYPE_FLOAT,  float,  float, 0.0)
@@ -1321,6 +1367,33 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
   }
 }
 
+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, bool preserve_proto_fieldnames) {
+  if (preserve_proto_fieldnames) {
+    if (desc->json_serialize_handlers == NULL) {
+      desc->json_serialize_handlers =
+          upb_json_printer_newhandlers(
+              desc->msgdef, true, &desc->json_serialize_handlers);
+    }
+    return desc->json_serialize_handlers;
+  } else {
+    if (desc->json_serialize_handlers_preserve == NULL) {
+      desc->json_serialize_handlers_preserve =
+          upb_json_printer_newhandlers(
+              desc->msgdef, false, &desc->json_serialize_handlers_preserve);
+    }
+    return desc->json_serialize_handlers_preserve;
+  }
+}
+
 /*
  * call-seq:
  *     MessageClass.encode(msg) => bytes
@@ -1343,8 +1416,8 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
     upb_pb_encoder* encoder;
     VALUE ret;
 
-    stackenv_init(&se, "Error occurred during encoding: %" PRIsVALUE);
-    encoder = upb_pb_encoder_create(se.arena, serialize_handlers, sink.sink);
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
 
     putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0, false, false, true);
 
@@ -1401,8 +1474,8 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
     stackenv se;
     VALUE ret;
 
-    stackenv_init(&se, "Error occurred during encoding: %" PRIsVALUE);
-    printer = upb_json_printer_create(se.arena, serialize_handlers, sink.sink);
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
 
     putmsg(msg_rb, desc, upb_json_printer_input(printer), 0,
            RTEST(emit_defaults), true, true);

+ 22 - 18
ruby/ext/google/protobuf_c/message.c

@@ -60,11 +60,6 @@ rb_data_type_t Message_type = {
 VALUE Message_alloc(VALUE klass) {
   VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
   Descriptor* desc = ruby_to_Descriptor(descriptor);
-
-  if (desc->layout == NULL) {
-    desc->layout = create_layout(desc);
-  }
-
   MessageHeader* msg = (MessageHeader*)ALLOC_N(
       uint8_t, sizeof(MessageHeader) + desc->layout->size);
   VALUE ret;
@@ -281,7 +276,7 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
   } else if (accessor_type == METHOD_PRESENCE) {
     return layout_has(self->descriptor->layout, Message_data(self), f);
   } else if (accessor_type == METHOD_ENUM_GETTER) {
-    VALUE enum_type = field_type_class(self->descriptor->layout, f);
+    VALUE enum_type = field_type_class(f);
     VALUE method = rb_intern("const_get");
     VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
 
@@ -325,13 +320,15 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
   }
 }
 
-VALUE create_submsg_from_hash(const MessageLayout* layout,
-                              const upb_fielddef* f, VALUE hash) {
-  const upb_msgdef *d = upb_fielddef_msgsubdef(f);
+VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
+  const upb_def *d = upb_fielddef_subdef(f);
   assert(d != NULL);
 
+  VALUE descriptor = get_def_obj(d);
+  VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
+
   VALUE args[1] = { hash };
-  return rb_class_new_instance(1, args, field_type_class(layout, f));
+  return rb_class_new_instance(1, args, msgclass);
 }
 
 int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
@@ -381,14 +378,14 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
     for (int i = 0; i < RARRAY_LEN(val); i++) {
       VALUE entry = rb_ary_entry(val, i);
       if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
-        entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
+        entry = create_submsg_from_hash(f, entry);
       }
 
       RepeatedField_push(ary, entry);
     }
   } else {
     if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
-      val = create_submsg_from_hash(self->descriptor->layout, f, val);
+      val = create_submsg_from_hash(f, val);
     }
 
     layout_set(self->descriptor->layout, Message_data(self), f, val);
@@ -633,11 +630,17 @@ VALUE Message_descriptor(VALUE klass) {
   return rb_ivar_get(klass, descriptor_instancevar_interned);
 }
 
-VALUE build_class_from_descriptor(VALUE descriptor) {
-  Descriptor* desc = ruby_to_Descriptor(descriptor);
+VALUE build_class_from_descriptor(Descriptor* desc) {
   const char *name;
   VALUE klass;
 
+  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);
+  }
+
   name = upb_msgdef_fullname(desc->msgdef);
   if (name == NULL) {
     rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
@@ -648,7 +651,8 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
       // their own toplevel constant class name.
       rb_intern("Message"),
       rb_cObject);
-  rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
+  rb_ivar_set(klass, descriptor_instancevar_interned,
+              get_def_obj(desc->msgdef));
   rb_define_alloc_func(klass, Message_alloc);
   rb_require("google/protobuf/message_exts");
   rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
@@ -733,8 +737,7 @@ VALUE enum_descriptor(VALUE self) {
   return rb_ivar_get(self, descriptor_instancevar_interned);
 }
 
-VALUE build_module_from_enumdesc(VALUE _enumdesc) {
-  EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
+VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
   VALUE mod = rb_define_module_id(
       rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
 
@@ -755,7 +758,8 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
   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_ivar_set(mod, descriptor_instancevar_interned, _enumdesc);
+  rb_ivar_set(mod, descriptor_instancevar_interned,
+              get_def_obj(enumdesc->enumdef));
 
   return mod;
 }

+ 19 - 3
ruby/ext/google/protobuf_c/protobuf.c

@@ -30,10 +30,26 @@
 
 #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;
+
 VALUE cError;
 VALUE cParseError;
 VALUE cTypeError;
-VALUE c_only_cookie;
+
+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.
@@ -100,6 +116,6 @@ void Init_protobuf_c() {
   kRubyStringASCIIEncoding = rb_usascii_encoding();
   kRubyString8bitEncoding = rb_ascii8bit_encoding();
 
-  rb_gc_register_address(&c_only_cookie);
-  c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
+  rb_gc_register_address(&upb_def_to_ruby_obj_map);
+  upb_def_to_ruby_obj_map = rb_hash_new();
 }

+ 48 - 62
ruby/ext/google/protobuf_c/protobuf.h

@@ -107,68 +107,62 @@ typedef struct Builder Builder;
 // -----------------------------------------------------------------------------
 
 struct DescriptorPool {
-  VALUE def_to_descriptor;  // Hash table of def* -> Ruby descriptor.
   upb_symtab* symtab;
-  upb_handlercache* fill_handler_cache;
-  upb_handlercache* pb_serialize_handler_cache;
-  upb_handlercache* json_serialize_handler_cache;
-  upb_handlercache* json_serialize_handler_preserve_cache;
-  upb_pbcodecache* fill_method_cache;
-  upb_json_codecache* json_fill_method_cache;
 };
 
 struct Descriptor {
   const upb_msgdef* msgdef;
   MessageLayout* layout;
-  VALUE klass;
-  VALUE descriptor_pool;
+  VALUE klass;  // begins as nil
+  const upb_handlers* fill_handlers;
+  const upb_pbdecodermethod* fill_method;
+  const upb_json_parsermethod* json_fill_method;
+  const upb_handlers* pb_serialize_handlers;
+  const upb_handlers* json_serialize_handlers;
+  const upb_handlers* json_serialize_handlers_preserve;
 };
 
 struct FileDescriptor {
   const upb_filedef* filedef;
-  VALUE descriptor_pool;  // Owns the upb_filedef.
 };
 
 struct FieldDescriptor {
   const upb_fielddef* fielddef;
-  VALUE descriptor_pool;  // Owns the upb_fielddef.
 };
 
 struct OneofDescriptor {
   const upb_oneofdef* oneofdef;
-  VALUE descriptor_pool;  // Owns the upb_oneofdef.
 };
 
 struct EnumDescriptor {
   const upb_enumdef* enumdef;
   VALUE module;  // begins as nil
-  VALUE descriptor_pool;  // Owns the upb_enumdef.
 };
 
 struct MessageBuilderContext {
-  google_protobuf_DescriptorProto* msg_proto;
-  VALUE file_builder;
+  VALUE descriptor;
+  VALUE builder;
 };
 
 struct OneofBuilderContext {
-  int oneof_index;
-  VALUE message_builder;
+  VALUE descriptor;
+  VALUE builder;
 };
 
 struct EnumBuilderContext {
-  google_protobuf_EnumDescriptorProto* enum_proto;
-  VALUE file_builder;
+  VALUE enumdesc;
 };
 
 struct FileBuilderContext {
-  upb_arena *arena;
-  google_protobuf_FileDescriptorProto* file_proto;
-  VALUE descriptor_pool;
+  VALUE pending_list;
+  VALUE file_descriptor;
+  VALUE builder;
 };
 
 struct Builder {
-  VALUE descriptor_pool;
-  VALUE default_file_builder;
+  VALUE pending_list;
+  VALUE default_file_descriptor;
+  upb_def** defs;  // used only while finalizing
 };
 
 extern VALUE cDescriptorPool;
@@ -197,6 +191,7 @@ 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(int argc, VALUE* argv, VALUE _self);
 VALUE DescriptorPool_lookup(VALUE _self, VALUE name);
 VALUE DescriptorPool_generated_pool(VALUE _self);
@@ -208,11 +203,13 @@ void Descriptor_free(void* _self);
 VALUE Descriptor_alloc(VALUE klass);
 void Descriptor_register(VALUE module);
 Descriptor* ruby_to_Descriptor(VALUE value);
-VALUE Descriptor_initialize(VALUE _self, VALUE cookie, VALUE descriptor_pool,
-                            VALUE ptr);
+VALUE Descriptor_initialize(VALUE _self, VALUE file_descriptor_rb);
 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_add_oneof(VALUE _self, VALUE obj);
 VALUE Descriptor_each_oneof(VALUE _self);
 VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name);
 VALUE Descriptor_msgclass(VALUE _self);
@@ -224,24 +221,28 @@ void FileDescriptor_free(void* _self);
 VALUE FileDescriptor_alloc(VALUE klass);
 void FileDescriptor_register(VALUE module);
 FileDescriptor* ruby_to_FileDescriptor(VALUE value);
-VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
-                                VALUE descriptor_pool, VALUE ptr);
+VALUE FileDescriptor_initialize(int argc, VALUE* argv, VALUE _self);
 VALUE FileDescriptor_name(VALUE _self);
 VALUE FileDescriptor_syntax(VALUE _self);
+VALUE FileDescriptor_syntax_set(VALUE _self, VALUE syntax);
 
 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_initialize(VALUE _self, VALUE cookie,
-                                 VALUE descriptor_pool, VALUE ptr);
 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_default(VALUE _self);
+VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value);
 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_has(VALUE _self, VALUE msg_rb);
 VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb);
@@ -255,20 +256,21 @@ void OneofDescriptor_free(void* _self);
 VALUE OneofDescriptor_alloc(VALUE klass);
 void OneofDescriptor_register(VALUE module);
 OneofDescriptor* ruby_to_OneofDescriptor(VALUE value);
-VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
-                                 VALUE descriptor_pool, VALUE ptr);
 VALUE OneofDescriptor_name(VALUE _self);
+VALUE OneofDescriptor_name_set(VALUE _self, VALUE value);
+VALUE OneofDescriptor_add_field(VALUE _self, VALUE field);
 VALUE OneofDescriptor_each(VALUE _self, VALUE field);
 
 void EnumDescriptor_mark(void* _self);
 void EnumDescriptor_free(void* _self);
 VALUE EnumDescriptor_alloc(VALUE klass);
-VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
-                                VALUE descriptor_pool, VALUE ptr);
 void EnumDescriptor_register(VALUE module);
 EnumDescriptor* ruby_to_EnumDescriptor(VALUE value);
+VALUE EnumDescriptor_initialize(VALUE _self, VALUE file_descriptor_rb);
 VALUE EnumDescriptor_file_descriptor(VALUE _self);
 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);
@@ -281,8 +283,8 @@ VALUE MessageBuilderContext_alloc(VALUE klass);
 void MessageBuilderContext_register(VALUE module);
 MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value);
 VALUE MessageBuilderContext_initialize(VALUE _self,
-                                       VALUE _file_builder,
-                                       VALUE name);
+                                       VALUE descriptor,
+                                       VALUE builder);
 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);
@@ -304,19 +306,15 @@ 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 _file_builder,
-                                    VALUE name);
+VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdesc);
 VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number);
 
 void FileBuilderContext_mark(void* _self);
 void FileBuilderContext_free(void* _self);
 VALUE FileBuilderContext_alloc(VALUE klass);
 void FileBuilderContext_register(VALUE module);
-FileBuilderContext* ruby_to_FileBuilderContext(VALUE _self);
-upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str);
-upb_strview FileBuilderContext_strdup_name(VALUE _self, VALUE rb_str);
-VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
-                                    VALUE name, VALUE options);
+VALUE FileBuilderContext_initialize(VALUE _self, VALUE file_descriptor,
+				    VALUE builder);
 VALUE FileBuilderContext_add_message(VALUE _self, VALUE name);
 VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name);
 VALUE FileBuilderContext_pending_descriptors(VALUE _self);
@@ -326,8 +324,7 @@ void Builder_free(void* _self);
 VALUE Builder_alloc(VALUE klass);
 void Builder_register(VALUE module);
 Builder* ruby_to_Builder(VALUE value);
-VALUE Builder_build(VALUE _self);
-VALUE Builder_initialize(VALUE _self, VALUE descriptor_pool);
+VALUE Builder_initialize(VALUE _self);
 VALUE Builder_add_file(int argc, VALUE *argv, VALUE _self);
 VALUE Builder_add_message(VALUE _self, VALUE name);
 VALUE Builder_add_enum(VALUE _self, VALUE name);
@@ -371,7 +368,7 @@ extern rb_encoding* kRubyStringUtf8Encoding;
 extern rb_encoding* kRubyStringASCIIEncoding;
 extern rb_encoding* kRubyString8bitEncoding;
 
-VALUE field_type_class(const MessageLayout* layout, const upb_fielddef* field);
+VALUE field_type_class(const upb_fielddef* field);
 
 #define MAP_KEY_FIELD 1
 #define MAP_VALUE_FIELD 2
@@ -504,15 +501,13 @@ struct MessageField {
   size_t hasbit;
 };
 
-// MessageLayout is owned by the enclosing Descriptor, which must outlive us.
 struct MessageLayout {
-  const Descriptor* desc;
   const upb_msgdef* msgdef;
   MessageField* fields;
   size_t size;
 };
 
-MessageLayout* create_layout(const Descriptor* desc);
+MessageLayout* create_layout(const upb_msgdef* msgdef);
 void free_layout(MessageLayout* layout);
 bool field_contains_hasbit(MessageLayout* layout,
                  const upb_fielddef* field);
@@ -561,7 +556,7 @@ struct MessageHeader {
 
 extern rb_data_type_t Message_type;
 
-VALUE build_class_from_descriptor(VALUE descriptor);
+VALUE build_class_from_descriptor(Descriptor* descriptor);
 void* Message_data(void* msg);
 void Message_mark(void* self);
 void Message_free(void* self);
@@ -585,13 +580,12 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass);
 VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb);
 VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
 
-VALUE build_module_from_enumdesc(VALUE _enumdesc);
+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);
-void add_handlers_for_message(const void *closure, upb_handlers *h);
 
 // Maximum depth allowed during encoding, to avoid stack overflows due to
 // cycles.
@@ -601,11 +595,8 @@ void add_handlers_for_message(const void *closure, upb_handlers *h);
 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
 // instances.
 // -----------------------------------------------------------------------------
-VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def);
-VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def);
-VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def);
-VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def);
-VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def);
+void add_def_obj(const void* def, VALUE value);
+VALUE get_def_obj(const void* def);
 
 // -----------------------------------------------------------------------------
 // Utilities.
@@ -621,9 +612,4 @@ void check_upb_status(const upb_status* status, const char* msg);
 
 extern ID descriptor_instancevar_interned;
 
-// A distinct object that is not accessible from Ruby.  We use this as a
-// constructor argument to enforce that certain objects cannot be created from
-// Ruby.
-extern VALUE c_only_cookie;
-
 #endif  // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__

+ 50 - 29
ruby/ext/google/protobuf_c/storage.c

@@ -430,10 +430,8 @@ static size_t align_up_to(size_t offset, size_t granularity) {
   return (offset + granularity - 1) & ~(granularity - 1);
 }
 
-MessageLayout* create_layout(const Descriptor* desc) {
-  const upb_msgdef *msgdef = desc->msgdef;
+MessageLayout* create_layout(const upb_msgdef* msgdef) {
   MessageLayout* layout = ALLOC(MessageLayout);
-  layout->desc = desc;
   int nfields = upb_msgdef_numfields(msgdef);
   upb_msg_field_iter it;
   upb_msg_oneof_iter oit;
@@ -450,7 +448,7 @@ MessageLayout* create_layout(const Descriptor* desc) {
       layout->fields[upb_fielddef_index(field)].hasbit = hasbit++;
     } else {
       layout->fields[upb_fielddef_index(field)].hasbit =
-          MESSAGE_FIELD_NO_HASBIT;
+	  MESSAGE_FIELD_NO_HASBIT;
     }
   }
 
@@ -539,25 +537,28 @@ MessageLayout* create_layout(const Descriptor* desc) {
   }
 
   layout->size = off;
+
   layout->msgdef = msgdef;
+  upb_msgdef_ref(layout->msgdef, &layout->msgdef);
 
   return layout;
 }
 
 void free_layout(MessageLayout* layout) {
   xfree(layout->fields);
+  upb_msgdef_unref(layout->msgdef, &layout->msgdef);
   xfree(layout);
 }
 
-VALUE field_type_class(const MessageLayout* layout, const upb_fielddef* field) {
+VALUE field_type_class(const upb_fielddef* field) {
   VALUE type_class = Qnil;
   if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
-    VALUE submsgdesc = get_msgdef_obj(layout->desc->descriptor_pool,
-                                      upb_fielddef_msgsubdef(field));
+    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_enumdef_obj(layout->desc->descriptor_pool,
-                                        upb_fielddef_enumsubdef(field));
+    VALUE subenumdesc =
+        get_def_obj(upb_fielddef_subdef(field));
     type_class = EnumDescriptor_enummodule(subenumdesc);
   }
   return type_class;
@@ -631,7 +632,7 @@ void layout_clear(MessageLayout* layout,
 
     const upb_fielddef* key_field = map_field_key(field);
     const upb_fielddef* value_field = map_field_value(field);
-    VALUE type_class = field_type_class(layout, value_field);
+    VALUE type_class = field_type_class(value_field);
 
     if (type_class != Qnil) {
       VALUE args[3] = {
@@ -652,7 +653,7 @@ void layout_clear(MessageLayout* layout,
   } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
     VALUE ary = Qnil;
 
-    VALUE type_class = field_type_class(layout, field);
+    VALUE type_class = field_type_class(field);
 
     if (type_class != Qnil) {
       VALUE args[2] = {
@@ -667,9 +668,9 @@ void layout_clear(MessageLayout* layout,
 
     DEREF(memory, VALUE) = ary;
   } else {
-    native_slot_set(upb_fielddef_name(field), upb_fielddef_type(field),
-                    field_type_class(layout, field), memory,
-                    layout_get_default(field));
+    native_slot_set(upb_fielddef_name(field),
+                    upb_fielddef_type(field), field_type_class(field),
+                    memory, layout_get_default(field));
   }
 }
 
@@ -727,19 +728,20 @@ VALUE layout_get(MessageLayout* layout,
       return layout_get_default(field);
     }
     return native_slot_get(upb_fielddef_type(field),
-                           field_type_class(layout, field), memory);
+                           field_type_class(field),
+                           memory);
   } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
     return *((VALUE *)memory);
   } else if (!field_set) {
     return layout_get_default(field);
   } else {
     return native_slot_get(upb_fielddef_type(field),
-                           field_type_class(layout, field), memory);
+                           field_type_class(field),
+                           memory);
   }
 }
 
-static void check_repeated_field_type(const MessageLayout* layout, VALUE val,
-                                      const upb_fielddef* field) {
+static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
   RepeatedField* self;
   assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
 
@@ -753,13 +755,25 @@ static void check_repeated_field_type(const MessageLayout* layout, VALUE val,
     rb_raise(cTypeError, "Repeated field array has wrong element type");
   }
 
-  if (self->field_type_class != field_type_class(layout, field)) {
-    rb_raise(cTypeError, "Repeated field array has wrong message/enum class");
+  if (self->field_type == UPB_TYPE_MESSAGE) {
+    if (self->field_type_class !=
+        Descriptor_msgclass(get_def_obj(upb_fielddef_subdef(field)))) {
+      rb_raise(cTypeError,
+               "Repeated field array has wrong message class");
+    }
+  }
+
+
+  if (self->field_type == UPB_TYPE_ENUM) {
+    if (self->field_type_class !=
+        EnumDescriptor_enummodule(get_def_obj(upb_fielddef_subdef(field)))) {
+      rb_raise(cTypeError,
+               "Repeated field array has wrong enum class");
+    }
   }
 }
 
-static void check_map_field_type(const MessageLayout* layout, VALUE val,
-                                 const upb_fielddef* field) {
+static void check_map_field_type(VALUE val, const upb_fielddef* field) {
   const upb_fielddef* key_field = map_field_key(field);
   const upb_fielddef* value_field = map_field_value(field);
   Map* self;
@@ -776,11 +790,17 @@ static void check_map_field_type(const MessageLayout* layout, VALUE val,
   if (self->value_type != upb_fielddef_type(value_field)) {
     rb_raise(cTypeError, "Map value type does not match field's value type");
   }
-  if (self->value_type_class != field_type_class(layout, value_field)) {
-    rb_raise(cTypeError, "Map value type has wrong message/enum class");
+  if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
+      upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
+    if (self->value_type_class !=
+        get_def_obj(upb_fielddef_subdef(value_field))) {
+      rb_raise(cTypeError,
+               "Map value type has wrong message/enum class");
+    }
   }
 }
 
+
 void layout_set(MessageLayout* layout,
                 void* storage,
                 const upb_fielddef* field,
@@ -808,19 +828,20 @@ void layout_set(MessageLayout* layout,
       // and case number are altered atomically (w.r.t. the Ruby VM).
       native_slot_set_value_and_case(
           upb_fielddef_name(field),
-          upb_fielddef_type(field), field_type_class(layout, field),
+          upb_fielddef_type(field), field_type_class(field),
           memory, val,
           oneof_case, upb_fielddef_number(field));
     }
   } else if (is_map_field(field)) {
-    check_map_field_type(layout, val, field);
+    check_map_field_type(val, field);
     DEREF(memory, VALUE) = val;
   } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
-    check_repeated_field_type(layout, val, field);
+    check_repeated_field_type(val, field);
     DEREF(memory, VALUE) = val;
   } else {
-    native_slot_set(upb_fielddef_name(field), upb_fielddef_type(field),
-                    field_type_class(layout, field), memory, val);
+    native_slot_set(upb_fielddef_name(field),
+                    upb_fielddef_type(field), field_type_class(field),
+                    memory, val);
   }
 
   if (layout->fields[upb_fielddef_index(field)].hasbit !=

文件差异内容过多而无法显示
+ 550 - 237
ruby/ext/google/protobuf_c/upb.c


文件差异内容过多而无法显示
+ 7244 - 4879
ruby/ext/google/protobuf_c/upb.h


+ 0 - 66
ruby/lib/google/protobuf.rb

@@ -50,72 +50,6 @@ else
   rescue LoadError
     require 'google/protobuf_c'
   end
-
-  module Google
-    module Protobuf
-      module Internal
-        def self.infer_package(names)
-          # Package is longest common prefix ending in '.', if any.
-          min, max = names.minmax
-          last_common_dot = nil
-          min.size.times { |i|
-            if min[i] != max[i] then break end
-            if min[i] == ?. then last_common_dot = i end
-          }
-          if last_common_dot
-            return min.slice(0, last_common_dot)
-          end
-        end
-
-        class NestingBuilder
-          def initialize(msg_names, enum_names)
-            @to_pos = {nil=>nil}
-            @msg_children = Hash.new { |hash, key| hash[key] = [] }
-            @enum_children = Hash.new { |hash, key| hash[key] = [] }
-
-            msg_names.each_with_index { |name, idx| @to_pos[name] = idx }
-            enum_names.each_with_index { |name, idx| @to_pos[name] = idx }
-
-            msg_names.each { |name| @msg_children[parent(name)] << name }
-            enum_names.each { |name| @enum_children[parent(name)] << name }
-          end
-
-          def build(package)
-            return build_msg(package)
-          end
-
-          private
-          def build_msg(msg)
-            return {
-              :pos => @to_pos[msg],
-              :msgs => @msg_children[msg].map { |child| build_msg(child) },
-              :enums => @enum_children[msg].map { |child| @to_pos[child] },
-            }
-          end
-
-          private
-          def parent(name)
-            idx = name.rindex(?.)
-            if idx
-              return name.slice(0, idx)
-            else
-              return nil
-            end
-          end
-        end
-
-        def self.fixup_descriptor(package, msg_names, enum_names)
-          if package.nil?
-            package = self.infer_package(msg_names + enum_names)
-          end
-
-          nesting = NestingBuilder.new(msg_names, enum_names).build(package)
-
-          return package, nesting
-        end
-      end
-    end
-  end
 end
 
 require 'google/protobuf/repeated_field'

+ 6 - 0
ruby/tests/basic.rb

@@ -17,6 +17,7 @@ module BasicTest
     add_message "BadFieldNames" do
       optional :dup, :int32, 1
       optional :class, :int32, 2
+      optional :"a.b", :int32, 3
     end
   end
 
@@ -350,6 +351,11 @@ module BasicTest
       assert nil != file_descriptor
       assert_equal "tests/basic_test.proto", file_descriptor.name
       assert_equal :proto3, file_descriptor.syntax
+
+      file_descriptor = BadFieldNames.descriptor.file_descriptor
+      assert nil != file_descriptor
+      assert_equal nil, file_descriptor.name
+      assert_equal :proto3, file_descriptor.syntax
     end
 
     def test_map_freeze

+ 1 - 0
ruby/tests/basic_proto2.rb

@@ -18,6 +18,7 @@ module BasicTestProto2
       add_message "BadFieldNames" do
         optional :dup, :int32, 1
         optional :class, :int32, 2
+        optional :"a.b", :int32, 3
       end
     end
   end

+ 9 - 5
ruby/tests/common_tests.rb

@@ -807,7 +807,7 @@ module CommonTests
                                                         proto_module::TestMessage2.new(:foo => 2)])
     data = proto_module::TestMessage.encode m
     m2 = proto_module::TestMessage.decode data
-    assert_equal m, m2
+    assert m == m2
 
     data = Google::Protobuf.encode m
     m2 = Google::Protobuf.decode(proto_module::TestMessage, data)
@@ -902,6 +902,8 @@ module CommonTests
     assert m['class'] == 2
     m['dup'] = 3
     assert m['dup'] == 3
+    m['a.b'] = 4
+    assert m['a.b'] == 4
   end
 
   def test_int_ranges
@@ -1082,7 +1084,9 @@ module CommonTests
 
     json_text = proto_module::TestMessage.encode_json(m)
     m2 = proto_module::TestMessage.decode_json(json_text)
-    assert_equal m, m2
+    puts m.inspect
+    puts m2.inspect
+    assert m == m2
 
     # Crash case from GitHub issue 283.
     bar = proto_module::Bar.new(msg: "bar")
@@ -1128,7 +1132,7 @@ module CommonTests
 
     actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
 
-    assert_equal expected, JSON.parse(actual, :symbolize_names => true)
+    assert JSON.parse(actual, :symbolize_names => true) == expected
   end
 
   def test_json_emit_defaults_submsg
@@ -1163,7 +1167,7 @@ module CommonTests
 
     actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
 
-    assert_equal expected, JSON.parse(actual, :symbolize_names => true)
+    assert JSON.parse(actual, :symbolize_names => true) == expected
   end
 
   def test_json_emit_defaults_repeated_submsg
@@ -1197,7 +1201,7 @@ module CommonTests
 
     actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
 
-    assert_equal expected, JSON.parse(actual, :symbolize_names => true)
+    assert JSON.parse(actual, :symbolize_names => true) == expected
   end
 
   def value_from_ruby(value)

+ 3 - 3
ruby/tests/type_errors.rb

@@ -10,11 +10,11 @@ require 'generated_code_pb'
 class TestTypeErrors < Test::Unit::TestCase
   def test_bad_string
     check_error Google::Protobuf::TypeError,
-                "Invalid argument for string field 'optional_string' (given Fixnum)." do
+                "Invalid argument for string field 'optional_string' (given Integer)." do
       A::B::C::TestMessage.new(optional_string: 4)
     end
     check_error Google::Protobuf::TypeError,
-                "Invalid argument for string field 'oneof_string' (given Fixnum)." do
+                "Invalid argument for string field 'oneof_string' (given Integer)." do
       A::B::C::TestMessage.new(oneof_string: 4)
     end
     check_error ArgumentError,
@@ -151,7 +151,7 @@ class TestTypeErrors < Test::Unit::TestCase
 
   def test_bad_msg
     check_error Google::Protobuf::TypeError,
-                "Invalid type Fixnum to assign to submessage field 'optional_msg'." do
+                "Invalid type Integer to assign to submessage field 'optional_msg'." do
       A::B::C::TestMessage.new(optional_msg: 2)
     end
     check_error Google::Protobuf::TypeError,

部分文件因为文件数量过多而无法显示