Implemented proto3 presence for Ruby. (#7406)

* WIP.

* WIP.

* Builds and runs. Tests need to be updated to test presence.

* Ruby: proto3 presence is passing all tests.

* Fixed a bug where empty messages has the wrong oneof count.
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index babdfa9..1a09cc5 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -1100,7 +1100,7 @@
  *     FieldDescriptor.has?(message) => boolean
  *
  * Returns whether the value is set on the given message. Raises an
- * exception when calling with proto syntax 3.
+ * exception when calling for fields that do not have presence.
  */
 VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
   DEFINE_SELF(FieldDescriptor, self, _self);
@@ -1434,6 +1434,7 @@
   rb_define_method(klass, "initialize",
                    MessageBuilderContext_initialize, 2);
   rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
+  rb_define_method(klass, "proto3_optional", MessageBuilderContext_proto3_optional, -1);
   rb_define_method(klass, "required", MessageBuilderContext_required, -1);
   rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
   rb_define_method(klass, "map", MessageBuilderContext_map, -1);
@@ -1469,7 +1470,8 @@
 
 static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
                              VALUE type, VALUE number, VALUE type_class,
-                             VALUE options, int oneof_index) {
+                             VALUE options, int oneof_index,
+                             bool proto3_optional) {
   DEFINE_SELF(MessageBuilderContext, self, msgbuilder_rb);
   FileBuilderContext* file_context =
       ruby_to_FileBuilderContext(self->file_builder);
@@ -1489,6 +1491,10 @@
   google_protobuf_FieldDescriptorProto_set_type(
       field_proto, (int)ruby_to_descriptortype(type));
 
+  if (proto3_optional) {
+    google_protobuf_FieldDescriptorProto_set_proto3_optional(field_proto, true);
+  }
+
   if (type_class != Qnil) {
     Check_Type(type_class, T_STRING);
 
@@ -1574,7 +1580,38 @@
   }
 
   msgdef_add_field(_self, UPB_LABEL_OPTIONAL, name, type, number, type_class,
-                   options, -1);
+                   options, -1, false);
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.proto3_optional(name, type, number,
+ *                                           type_class = nil, options = nil)
+ *
+ * Defines a true proto3 optional field (that tracks presence) 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_proto3_optional(int argc, VALUE* argv,
+                                            VALUE _self) {
+  VALUE name, type, number;
+  VALUE type_class, options = Qnil;
+
+  rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
+
+  // Allow passing (name, type, number, options) or
+  // (name, type, number, type_class, options)
+  if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
+    options = type_class;
+    type_class = Qnil;
+  }
+
+  msgdef_add_field(_self, UPB_LABEL_OPTIONAL, name, type, number, type_class,
+                   options, -1, true);
 
   return Qnil;
 }
@@ -1607,7 +1644,7 @@
   }
 
   msgdef_add_field(_self, UPB_LABEL_REQUIRED, name, type, number, type_class,
-                   options, -1);
+                   options, -1, false);
 
   return Qnil;
 }
@@ -1633,7 +1670,7 @@
   type_class = (argc > 3) ? argv[3] : Qnil;
 
   msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
-                   Qnil, -1);
+                   Qnil, -1, false);
 
   return Qnil;
 }
@@ -1758,6 +1795,56 @@
   return Qnil;
 }
 
+void MessageBuilderContext_add_synthetic_oneofs(VALUE _self) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  FileBuilderContext* file_context =
+      ruby_to_FileBuilderContext(self->file_builder);
+  size_t field_count, oneof_count;
+  google_protobuf_FieldDescriptorProto** fields =
+      google_protobuf_DescriptorProto_mutable_field(self->msg_proto, &field_count);
+  const google_protobuf_OneofDescriptorProto*const* oneofs =
+      google_protobuf_DescriptorProto_oneof_decl(self->msg_proto, &oneof_count);
+  VALUE names = rb_hash_new();
+  VALUE underscore = rb_str_new2("_");
+  size_t i;
+
+  // We have to build a set of all names, to ensure that synthetic oneofs are
+  // not creating conflicts.
+  for (i = 0; i < field_count; i++) {
+    upb_strview name = google_protobuf_FieldDescriptorProto_name(fields[i]);
+    rb_hash_aset(names, rb_str_new(name.data, name.size), Qtrue);
+  }
+  for (i = 0; i < oneof_count; i++) {
+    upb_strview name = google_protobuf_OneofDescriptorProto_name(oneofs[i]);
+    rb_hash_aset(names, rb_str_new(name.data, name.size), Qtrue);
+  }
+
+  for (i = 0; i < field_count; i++) {
+    google_protobuf_OneofDescriptorProto* oneof_proto;
+    VALUE oneof_name;
+    upb_strview field_name;
+
+    if (!google_protobuf_FieldDescriptorProto_proto3_optional(fields[i])) {
+      continue;
+    }
+
+    // Prepend '_' until we are no longer conflicting.
+    field_name = google_protobuf_FieldDescriptorProto_name(fields[i]);
+    oneof_name = rb_str_new(field_name.data, field_name.size);
+    while (rb_hash_lookup(names, oneof_name) != Qnil) {
+      oneof_name = rb_str_plus(underscore, oneof_name);
+    }
+
+    rb_hash_aset(names, oneof_name, Qtrue);
+    google_protobuf_FieldDescriptorProto_set_oneof_index(fields[i],
+                                                         oneof_count++);
+    oneof_proto = google_protobuf_DescriptorProto_add_oneof_decl(
+        self->msg_proto, file_context->arena);
+    google_protobuf_OneofDescriptorProto_set_name(
+        oneof_proto, FileBuilderContext_strdup(self->file_builder, oneof_name));
+  }
+}
+
 // -----------------------------------------------------------------------------
 // OneofBuilderContext.
 // -----------------------------------------------------------------------------
@@ -1829,7 +1916,7 @@
   rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
 
   msgdef_add_field(self->message_builder, UPB_LABEL_OPTIONAL, name, type,
-                   number, type_class, options, self->oneof_index);
+                   number, type_class, options, self->oneof_index, false);
 
   return Qnil;
 }
@@ -2033,6 +2120,7 @@
   VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
   VALUE block = rb_block_proc();
   rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+  MessageBuilderContext_add_synthetic_oneofs(ctx);
   return Qnil;
 }