• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <ctype.h>
32 #include <errno.h>
33 #include "protobuf.h"
34 
35 // -----------------------------------------------------------------------------
36 // Common utilities.
37 // -----------------------------------------------------------------------------
38 
get_str(VALUE str)39 static const char* get_str(VALUE str) {
40   Check_Type(str, T_STRING);
41   return RSTRING_PTR(str);
42 }
43 
rb_str_maybe_null(const char * s)44 static VALUE rb_str_maybe_null(const char* s) {
45   if (s == NULL) {
46     s = "";
47   }
48   return rb_str_new2(s);
49 }
50 
rewrite_enum_default(const upb_symtab * symtab,google_protobuf_FileDescriptorProto * file,google_protobuf_FieldDescriptorProto * field)51 static void rewrite_enum_default(const upb_symtab* symtab,
52                                  google_protobuf_FileDescriptorProto* file,
53                                  google_protobuf_FieldDescriptorProto* field) {
54   upb_strview defaultval;
55   const char *type_name_str;
56   char *end;
57   long val;
58   const upb_enumdef *e;
59   upb_strview type_name;
60 
61   /* Look for TYPE_ENUM fields that have a default. */
62   if (google_protobuf_FieldDescriptorProto_type(field) !=
63           google_protobuf_FieldDescriptorProto_TYPE_ENUM ||
64       !google_protobuf_FieldDescriptorProto_has_default_value(field) ||
65       !google_protobuf_FieldDescriptorProto_has_type_name(field)) {
66     return;
67   }
68 
69   defaultval = google_protobuf_FieldDescriptorProto_default_value(field);
70   type_name = google_protobuf_FieldDescriptorProto_type_name(field);
71 
72   if (defaultval.size == 0 || !isdigit(defaultval.data[0])) {
73     return;
74   }
75 
76   if (type_name.size == 0 || type_name.data[0] != '.') {
77     return;
78   }
79 
80   type_name_str = type_name.data + 1;
81 
82   errno = 0;
83   val = strtol(defaultval.data, &end, 10);
84 
85   if (errno != 0 || *end != 0 || val < INT32_MIN || val > INT32_MAX) {
86     return;
87   }
88 
89   /* Now find the corresponding enum definition. */
90   e = upb_symtab_lookupenum(symtab, type_name_str);
91   if (e) {
92     /* Look in previously loaded files. */
93     const char *label = upb_enumdef_iton(e, val);
94     if (!label) {
95       return;
96     }
97     google_protobuf_FieldDescriptorProto_set_default_value(
98         field, upb_strview_makez(label));
99   } else {
100     /* Look in enums defined in this file. */
101     const google_protobuf_EnumDescriptorProto* matching_enum = NULL;
102     size_t i, n;
103     const google_protobuf_EnumDescriptorProto* const* enums =
104         google_protobuf_FileDescriptorProto_enum_type(file, &n);
105     const google_protobuf_EnumValueDescriptorProto* const* values;
106 
107     for (i = 0; i < n; i++) {
108       if (upb_strview_eql(google_protobuf_EnumDescriptorProto_name(enums[i]),
109                           upb_strview_makez(type_name_str))) {
110         matching_enum = enums[i];
111         break;
112       }
113     }
114 
115     if (!matching_enum) {
116       return;
117     }
118 
119     values = google_protobuf_EnumDescriptorProto_value(matching_enum, &n);
120     for (i = 0; i < n; i++) {
121       if (google_protobuf_EnumValueDescriptorProto_number(values[i]) == val) {
122         google_protobuf_FieldDescriptorProto_set_default_value(
123             field, google_protobuf_EnumValueDescriptorProto_name(values[i]));
124         return;
125       }
126     }
127 
128     /* We failed to find an enum default.  But we'll just leave the enum
129      * untouched and let the normal def-building code catch it. */
130   }
131 }
132 
133 /* Historically we allowed enum defaults to be specified as a number.  In
134  * retrospect this was a mistake as descriptors require defaults to be
135  * specified as a label. This can make a difference if multiple labels have the
136  * same number.
137  *
138  * Here we do a pass over all enum defaults and rewrite numeric defaults by
139  * looking up their labels.  This is complicated by the fact that the enum
140  * definition can live in either the symtab or the file_proto.
141  * */
rewrite_enum_defaults(const upb_symtab * symtab,google_protobuf_FileDescriptorProto * file_proto)142 static void rewrite_enum_defaults(
143     const upb_symtab* symtab, google_protobuf_FileDescriptorProto* file_proto) {
144   size_t i, n;
145   google_protobuf_DescriptorProto** msgs =
146       google_protobuf_FileDescriptorProto_mutable_message_type(file_proto, &n);
147 
148   for (i = 0; i < n; i++) {
149     size_t j, m;
150     google_protobuf_FieldDescriptorProto** fields =
151         google_protobuf_DescriptorProto_mutable_field(msgs[i], &m);
152     for (j = 0; j < m; j++) {
153       rewrite_enum_default(symtab, file_proto, fields[j]);
154     }
155   }
156 }
157 
remove_path(upb_strview * name)158 static void remove_path(upb_strview *name) {
159   const char* last = strrchr(name->data, '.');
160   if (last) {
161     size_t remove = last - name->data + 1;
162     name->data += remove;
163     name->size -= remove;
164   }
165 }
166 
rewrite_nesting(VALUE msg_ent,google_protobuf_DescriptorProto * msg,google_protobuf_DescriptorProto * const * msgs,google_protobuf_EnumDescriptorProto * const * enums,upb_arena * arena)167 static void rewrite_nesting(VALUE msg_ent, google_protobuf_DescriptorProto* msg,
168                             google_protobuf_DescriptorProto* const* msgs,
169                             google_protobuf_EnumDescriptorProto* const* enums,
170                             upb_arena *arena) {
171   VALUE submsgs = rb_hash_aref(msg_ent, ID2SYM(rb_intern("msgs")));
172   VALUE enum_pos = rb_hash_aref(msg_ent, ID2SYM(rb_intern("enums")));
173   int submsg_count;
174   int enum_count;
175   int i;
176   google_protobuf_DescriptorProto** msg_msgs;
177   google_protobuf_EnumDescriptorProto** msg_enums;
178 
179   Check_Type(submsgs, T_ARRAY);
180   Check_Type(enum_pos, T_ARRAY);
181 
182   submsg_count = RARRAY_LEN(submsgs);
183   enum_count = RARRAY_LEN(enum_pos);
184 
185   msg_msgs = google_protobuf_DescriptorProto_resize_nested_type(
186       msg, submsg_count, arena);
187   msg_enums =
188       google_protobuf_DescriptorProto_resize_enum_type(msg, enum_count, arena);
189 
190   for (i = 0; i < submsg_count; i++) {
191     VALUE submsg_ent = RARRAY_PTR(submsgs)[i];
192     VALUE pos = rb_hash_aref(submsg_ent, ID2SYM(rb_intern("pos")));
193     upb_strview name;
194 
195     msg_msgs[i] = msgs[NUM2INT(pos)];
196     name = google_protobuf_DescriptorProto_name(msg_msgs[i]);
197     remove_path(&name);
198     google_protobuf_DescriptorProto_set_name(msg_msgs[i], name);
199     rewrite_nesting(submsg_ent, msg_msgs[i], msgs, enums, arena);
200   }
201 
202   for (i = 0; i < enum_count; i++) {
203     VALUE pos = RARRAY_PTR(enum_pos)[i];
204     msg_enums[i] = enums[NUM2INT(pos)];
205   }
206 }
207 
208 /* We have to do some relatively complicated logic here for backward
209  * compatibility.
210  *
211  * In descriptor.proto, messages are nested inside other messages if that is
212  * what the original .proto file looks like.  For example, suppose we have this
213  * foo.proto:
214  *
215  * package foo;
216  * message Bar {
217  *   message Baz {}
218  * }
219  *
220  * The descriptor for this must look like this:
221  *
222  * file {
223  *   name: "test.proto"
224  *   package: "foo"
225  *   message_type {
226  *     name: "Bar"
227  *     nested_type {
228  *       name: "Baz"
229  *     }
230  *   }
231  * }
232  *
233  * However, the Ruby generated code has always generated messages in a flat,
234  * non-nested way:
235  *
236  * Google::Protobuf::DescriptorPool.generated_pool.build do
237  *   add_message "foo.Bar" do
238  *   end
239  *   add_message "foo.Bar.Baz" do
240  *   end
241  * end
242  *
243  * Here we need to do a translation where we turn this generated code into the
244  * above descriptor.  We need to infer that "foo" is the package name, and not
245  * a message itself.
246  *
247  * We delegate to Ruby to compute the transformation, for more concice and
248  * readable code than we can do in C */
rewrite_names(VALUE _file_builder,google_protobuf_FileDescriptorProto * file_proto)249 static void rewrite_names(VALUE _file_builder,
250                           google_protobuf_FileDescriptorProto* file_proto) {
251   FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
252   upb_arena *arena = file_builder->arena;
253   // Build params (package, msg_names, enum_names).
254   VALUE package = Qnil;
255   VALUE msg_names = rb_ary_new();
256   VALUE enum_names = rb_ary_new();
257   size_t msg_count, enum_count, i;
258   VALUE new_package, nesting, msg_ents, enum_ents;
259   google_protobuf_DescriptorProto** msgs;
260   google_protobuf_EnumDescriptorProto** enums;
261 
262   if (google_protobuf_FileDescriptorProto_has_package(file_proto)) {
263     upb_strview package_str =
264         google_protobuf_FileDescriptorProto_package(file_proto);
265     package = rb_str_new(package_str.data, package_str.size);
266   }
267 
268   msgs = google_protobuf_FileDescriptorProto_mutable_message_type(file_proto,
269                                                                   &msg_count);
270   for (i = 0; i < msg_count; i++) {
271     upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
272     rb_ary_push(msg_names, rb_str_new(name.data, name.size));
273   }
274 
275   enums = google_protobuf_FileDescriptorProto_mutable_enum_type(file_proto,
276                                                                 &enum_count);
277   for (i = 0; i < enum_count; i++) {
278     upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
279     rb_ary_push(enum_names, rb_str_new(name.data, name.size));
280   }
281 
282   {
283     // Call Ruby code to calculate package name and nesting.
284     VALUE args[3] = { package, msg_names, enum_names };
285     VALUE internal = rb_eval_string("Google::Protobuf::Internal");
286     VALUE ret = rb_funcallv(internal, rb_intern("fixup_descriptor"), 3, args);
287 
288     new_package = rb_ary_entry(ret, 0);
289     nesting = rb_ary_entry(ret, 1);
290   }
291 
292   // Rewrite package and names.
293   if (new_package != Qnil) {
294     upb_strview new_package_str =
295         FileBuilderContext_strdup(_file_builder, new_package);
296     google_protobuf_FileDescriptorProto_set_package(file_proto,
297                                                     new_package_str);
298   }
299 
300   for (i = 0; i < msg_count; i++) {
301     upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
302     remove_path(&name);
303     google_protobuf_DescriptorProto_set_name(msgs[i], name);
304   }
305 
306   for (i = 0; i < enum_count; i++) {
307     upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
308     remove_path(&name);
309     google_protobuf_EnumDescriptorProto_set_name(enums[i], name);
310   }
311 
312   // Rewrite nesting.
313   msg_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("msgs")));
314   enum_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("enums")));
315 
316   Check_Type(msg_ents, T_ARRAY);
317   Check_Type(enum_ents, T_ARRAY);
318 
319   for (i = 0; i < (size_t)RARRAY_LEN(msg_ents); i++) {
320     VALUE msg_ent = rb_ary_entry(msg_ents, i);
321     VALUE pos = rb_hash_aref(msg_ent, ID2SYM(rb_intern("pos")));
322     msgs[i] = msgs[NUM2INT(pos)];
323     rewrite_nesting(msg_ent, msgs[i], msgs, enums, arena);
324   }
325 
326   for (i = 0; i < (size_t)RARRAY_LEN(enum_ents); i++) {
327     VALUE enum_pos = rb_ary_entry(enum_ents, i);
328     enums[i] = enums[NUM2INT(enum_pos)];
329   }
330 
331   google_protobuf_FileDescriptorProto_resize_message_type(
332       file_proto, RARRAY_LEN(msg_ents), arena);
333   google_protobuf_FileDescriptorProto_resize_enum_type(
334       file_proto, RARRAY_LEN(enum_ents), arena);
335 }
336 
337 // -----------------------------------------------------------------------------
338 // DescriptorPool.
339 // -----------------------------------------------------------------------------
340 
341 #define DEFINE_CLASS(name, string_name)                             \
342     VALUE c ## name = Qnil;                                         \
343     const rb_data_type_t _ ## name ## _type = {                     \
344       string_name,                                                  \
345       { name ## _mark, name ## _free, NULL },                       \
346     };                                                              \
347     name* ruby_to_ ## name(VALUE val) {                             \
348       name* ret;                                                    \
349       TypedData_Get_Struct(val, name, &_ ## name ## _type, ret);    \
350       return ret;                                                   \
351     }                                                               \
352 
353 #define DEFINE_SELF(type, var, rb_var)                              \
354     type* var = ruby_to_ ## type(rb_var)
355 
356 // Global singleton DescriptorPool. The user is free to create others, but this
357 // is used by generated code.
358 VALUE generated_pool = Qnil;
359 
360 DEFINE_CLASS(DescriptorPool, "Google::Protobuf::DescriptorPool");
361 
DescriptorPool_mark(void * _self)362 void DescriptorPool_mark(void* _self) {
363   DescriptorPool* self = _self;
364   rb_gc_mark(self->def_to_descriptor);
365 }
366 
DescriptorPool_free(void * _self)367 void DescriptorPool_free(void* _self) {
368   DescriptorPool* self = _self;
369 
370   upb_symtab_free(self->symtab);
371   upb_handlercache_free(self->fill_handler_cache);
372   upb_handlercache_free(self->pb_serialize_handler_cache);
373   upb_handlercache_free(self->json_serialize_handler_cache);
374   upb_handlercache_free(self->json_serialize_handler_preserve_cache);
375   upb_pbcodecache_free(self->fill_method_cache);
376   upb_json_codecache_free(self->json_fill_method_cache);
377 
378   xfree(self);
379 }
380 
381 /*
382  * call-seq:
383  *     DescriptorPool.new => pool
384  *
385  * Creates a new, empty, descriptor pool.
386  */
DescriptorPool_alloc(VALUE klass)387 VALUE DescriptorPool_alloc(VALUE klass) {
388   DescriptorPool* self = ALLOC(DescriptorPool);
389   VALUE ret;
390 
391   self->def_to_descriptor = Qnil;
392   ret = TypedData_Wrap_Struct(klass, &_DescriptorPool_type, self);
393 
394   self->def_to_descriptor = rb_hash_new();
395   self->symtab = upb_symtab_new();
396   self->fill_handler_cache =
397       upb_handlercache_new(add_handlers_for_message, (void*)ret);
398   self->pb_serialize_handler_cache = upb_pb_encoder_newcache();
399   self->json_serialize_handler_cache = upb_json_printer_newcache(false);
400   self->json_serialize_handler_preserve_cache =
401       upb_json_printer_newcache(true);
402   self->fill_method_cache = upb_pbcodecache_new(self->fill_handler_cache);
403   self->json_fill_method_cache = upb_json_codecache_new();
404 
405   return ret;
406 }
407 
DescriptorPool_register(VALUE module)408 void DescriptorPool_register(VALUE module) {
409   VALUE klass = rb_define_class_under(
410       module, "DescriptorPool", rb_cObject);
411   rb_define_alloc_func(klass, DescriptorPool_alloc);
412   rb_define_method(klass, "build", DescriptorPool_build, -1);
413   rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
414   rb_define_singleton_method(klass, "generated_pool",
415                              DescriptorPool_generated_pool, 0);
416   rb_gc_register_address(&cDescriptorPool);
417   cDescriptorPool = klass;
418 
419   rb_gc_register_address(&generated_pool);
420   generated_pool = rb_class_new_instance(0, NULL, klass);
421 }
422 
423 /*
424  * call-seq:
425  *     DescriptorPool.build(&block)
426  *
427  * Invokes the block with a Builder instance as self. All message and enum types
428  * added within the block are committed to the pool atomically, and may refer
429  * (co)recursively to each other. The user should call Builder#add_message and
430  * Builder#add_enum within the block as appropriate.  This is the recommended,
431  * idiomatic way to define new message and enum types.
432  */
DescriptorPool_build(int argc,VALUE * argv,VALUE _self)433 VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self) {
434   VALUE ctx = rb_class_new_instance(1, &_self, cBuilder);
435   VALUE block = rb_block_proc();
436   rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
437   Builder_build(ctx);
438   return Qnil;
439 }
440 
441 /*
442  * call-seq:
443  *     DescriptorPool.lookup(name) => descriptor
444  *
445  * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
446  * exists with the given name.
447  */
DescriptorPool_lookup(VALUE _self,VALUE name)448 VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
449   DEFINE_SELF(DescriptorPool, self, _self);
450   const char* name_str = get_str(name);
451   const upb_msgdef* msgdef;
452   const upb_enumdef* enumdef;
453 
454   msgdef = upb_symtab_lookupmsg(self->symtab, name_str);
455   if (msgdef) {
456     return get_msgdef_obj(_self, msgdef);
457   }
458 
459   enumdef = upb_symtab_lookupenum(self->symtab, name_str);
460   if (enumdef) {
461     return get_enumdef_obj(_self, enumdef);
462   }
463 
464   return Qnil;
465 }
466 
467 /*
468  * call-seq:
469  *     DescriptorPool.generated_pool => descriptor_pool
470  *
471  * Class method that returns the global DescriptorPool. This is a singleton into
472  * which generated-code message and enum types are registered. The user may also
473  * register types in this pool for convenience so that they do not have to hold
474  * a reference to a private pool instance.
475  */
DescriptorPool_generated_pool(VALUE _self)476 VALUE DescriptorPool_generated_pool(VALUE _self) {
477   return generated_pool;
478 }
479 
480 // -----------------------------------------------------------------------------
481 // Descriptor.
482 // -----------------------------------------------------------------------------
483 
484 DEFINE_CLASS(Descriptor, "Google::Protobuf::Descriptor");
485 
Descriptor_mark(void * _self)486 void Descriptor_mark(void* _self) {
487   Descriptor* self = _self;
488   rb_gc_mark(self->klass);
489   rb_gc_mark(self->descriptor_pool);
490   if (self->layout && self->layout->empty_template) {
491     layout_mark(self->layout, self->layout->empty_template);
492   }
493 }
494 
Descriptor_free(void * _self)495 void Descriptor_free(void* _self) {
496   Descriptor* self = _self;
497   if (self->layout) {
498     free_layout(self->layout);
499   }
500   xfree(self);
501 }
502 
503 /*
504  * call-seq:
505  *     Descriptor.new => descriptor
506  *
507  * Creates a new, empty, message type descriptor. At a minimum, its name must be
508  * set before it is added to a pool. It cannot be used to create messages until
509  * it is added to a pool, after which it becomes immutable (as part of a
510  * finalization process).
511  */
Descriptor_alloc(VALUE klass)512 VALUE Descriptor_alloc(VALUE klass) {
513   Descriptor* self = ALLOC(Descriptor);
514   VALUE ret = TypedData_Wrap_Struct(klass, &_Descriptor_type, self);
515   self->msgdef = NULL;
516   self->klass = Qnil;
517   self->descriptor_pool = Qnil;
518   self->layout = NULL;
519   return ret;
520 }
521 
Descriptor_register(VALUE module)522 void Descriptor_register(VALUE module) {
523   VALUE klass = rb_define_class_under(
524       module, "Descriptor", rb_cObject);
525   rb_define_alloc_func(klass, Descriptor_alloc);
526   rb_define_method(klass, "initialize", Descriptor_initialize, 3);
527   rb_define_method(klass, "each", Descriptor_each, 0);
528   rb_define_method(klass, "lookup", Descriptor_lookup, 1);
529   rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
530   rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
531   rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
532   rb_define_method(klass, "name", Descriptor_name, 0);
533   rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0);
534   rb_include_module(klass, rb_mEnumerable);
535   rb_gc_register_address(&cDescriptor);
536   cDescriptor = klass;
537 }
538 
539 /*
540  * call-seq:
541  *    Descriptor.new(c_only_cookie, ptr) => Descriptor
542  *
543  * Creates a descriptor wrapper object.  May only be called from C.
544  */
Descriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)545 VALUE Descriptor_initialize(VALUE _self, VALUE cookie,
546                             VALUE descriptor_pool, VALUE ptr) {
547   DEFINE_SELF(Descriptor, self, _self);
548 
549   if (cookie != c_only_cookie) {
550     rb_raise(rb_eRuntimeError,
551              "Descriptor objects may not be created from Ruby.");
552   }
553 
554   self->descriptor_pool = descriptor_pool;
555   self->msgdef = (const upb_msgdef*)NUM2ULL(ptr);
556 
557   return Qnil;
558 }
559 
560 /*
561  * call-seq:
562  *    Descriptor.file_descriptor
563  *
564  * Returns the FileDescriptor object this message belongs to.
565  */
Descriptor_file_descriptor(VALUE _self)566 VALUE Descriptor_file_descriptor(VALUE _self) {
567   DEFINE_SELF(Descriptor, self, _self);
568   return get_filedef_obj(self->descriptor_pool, upb_msgdef_file(self->msgdef));
569 }
570 
571 /*
572  * call-seq:
573  *     Descriptor.name => name
574  *
575  * Returns the name of this message type as a fully-qualified string (e.g.,
576  * My.Package.MessageType).
577  */
Descriptor_name(VALUE _self)578 VALUE Descriptor_name(VALUE _self) {
579   DEFINE_SELF(Descriptor, self, _self);
580   return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef));
581 }
582 
583 /*
584  * call-seq:
585  *     Descriptor.each(&block)
586  *
587  * Iterates over fields in this message type, yielding to the block on each one.
588  */
Descriptor_each(VALUE _self)589 VALUE Descriptor_each(VALUE _self) {
590   DEFINE_SELF(Descriptor, self, _self);
591 
592   upb_msg_field_iter it;
593   for (upb_msg_field_begin(&it, self->msgdef);
594        !upb_msg_field_done(&it);
595        upb_msg_field_next(&it)) {
596     const upb_fielddef* field = upb_msg_iter_field(&it);
597     VALUE obj = get_fielddef_obj(self->descriptor_pool, field);
598     rb_yield(obj);
599   }
600   return Qnil;
601 }
602 
603 /*
604  * call-seq:
605  *     Descriptor.lookup(name) => FieldDescriptor
606  *
607  * Returns the field descriptor for the field with the given name, if present,
608  * or nil if none.
609  */
Descriptor_lookup(VALUE _self,VALUE name)610 VALUE Descriptor_lookup(VALUE _self, VALUE name) {
611   DEFINE_SELF(Descriptor, self, _self);
612   const char* s = get_str(name);
613   const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
614   if (field == NULL) {
615     return Qnil;
616   }
617   return get_fielddef_obj(self->descriptor_pool, field);
618 }
619 
620 /*
621  * call-seq:
622  *     Descriptor.each_oneof(&block) => nil
623  *
624  * Invokes the given block for each oneof in this message type, passing the
625  * corresponding OneofDescriptor.
626  */
Descriptor_each_oneof(VALUE _self)627 VALUE Descriptor_each_oneof(VALUE _self) {
628   DEFINE_SELF(Descriptor, self, _self);
629 
630   upb_msg_oneof_iter it;
631   for (upb_msg_oneof_begin(&it, self->msgdef);
632        !upb_msg_oneof_done(&it);
633        upb_msg_oneof_next(&it)) {
634     const upb_oneofdef* oneof = upb_msg_iter_oneof(&it);
635     VALUE obj = get_oneofdef_obj(self->descriptor_pool, oneof);
636     rb_yield(obj);
637   }
638   return Qnil;
639 }
640 
641 /*
642  * call-seq:
643  *     Descriptor.lookup_oneof(name) => OneofDescriptor
644  *
645  * Returns the oneof descriptor for the oneof with the given name, if present,
646  * or nil if none.
647  */
Descriptor_lookup_oneof(VALUE _self,VALUE name)648 VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
649   DEFINE_SELF(Descriptor, self, _self);
650   const char* s = get_str(name);
651   const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
652   if (oneof == NULL) {
653     return Qnil;
654   }
655   return get_oneofdef_obj(self->descriptor_pool, oneof);
656 }
657 
658 /*
659  * call-seq:
660  *     Descriptor.msgclass => message_klass
661  *
662  * Returns the Ruby class created for this message type.
663  */
Descriptor_msgclass(VALUE _self)664 VALUE Descriptor_msgclass(VALUE _self) {
665   DEFINE_SELF(Descriptor, self, _self);
666   if (self->klass == Qnil) {
667     self->klass = build_class_from_descriptor(_self);
668   }
669   return self->klass;
670 }
671 
672 // -----------------------------------------------------------------------------
673 // FileDescriptor.
674 // -----------------------------------------------------------------------------
675 
676 DEFINE_CLASS(FileDescriptor, "Google::Protobuf::FileDescriptor");
677 
FileDescriptor_mark(void * _self)678 void FileDescriptor_mark(void* _self) {
679   FileDescriptor* self = _self;
680   rb_gc_mark(self->descriptor_pool);
681 }
682 
FileDescriptor_free(void * _self)683 void FileDescriptor_free(void* _self) {
684   xfree(_self);
685 }
686 
FileDescriptor_alloc(VALUE klass)687 VALUE FileDescriptor_alloc(VALUE klass) {
688   FileDescriptor* self = ALLOC(FileDescriptor);
689   VALUE ret = TypedData_Wrap_Struct(klass, &_FileDescriptor_type, self);
690   self->descriptor_pool = Qnil;
691   self->filedef = NULL;
692   return ret;
693 }
694 
695 /*
696  * call-seq:
697  *     FileDescriptor.new => file
698  *
699  * Returns a new file descriptor. The syntax must be set before it's passed
700  * to a builder.
701  */
FileDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)702 VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
703                                 VALUE descriptor_pool, VALUE ptr) {
704   DEFINE_SELF(FileDescriptor, self, _self);
705 
706   if (cookie != c_only_cookie) {
707     rb_raise(rb_eRuntimeError,
708              "Descriptor objects may not be created from Ruby.");
709   }
710 
711   self->descriptor_pool = descriptor_pool;
712   self->filedef = (const upb_filedef*)NUM2ULL(ptr);
713 
714   return Qnil;
715 }
716 
FileDescriptor_register(VALUE module)717 void FileDescriptor_register(VALUE module) {
718   VALUE klass = rb_define_class_under(
719       module, "FileDescriptor", rb_cObject);
720   rb_define_alloc_func(klass, FileDescriptor_alloc);
721   rb_define_method(klass, "initialize", FileDescriptor_initialize, 3);
722   rb_define_method(klass, "name", FileDescriptor_name, 0);
723   rb_define_method(klass, "syntax", FileDescriptor_syntax, 0);
724   rb_gc_register_address(&cFileDescriptor);
725   cFileDescriptor = klass;
726 }
727 
728 /*
729  * call-seq:
730  *     FileDescriptor.name => name
731  *
732  * Returns the name of the file.
733  */
FileDescriptor_name(VALUE _self)734 VALUE FileDescriptor_name(VALUE _self) {
735   DEFINE_SELF(FileDescriptor, self, _self);
736   const char* name = upb_filedef_name(self->filedef);
737   return name == NULL ? Qnil : rb_str_new2(name);
738 }
739 
740 /*
741  * call-seq:
742  *     FileDescriptor.syntax => syntax
743  *
744  * Returns this file descriptors syntax.
745  *
746  * Valid syntax versions are:
747  *     :proto2 or :proto3.
748  */
FileDescriptor_syntax(VALUE _self)749 VALUE FileDescriptor_syntax(VALUE _self) {
750   DEFINE_SELF(FileDescriptor, self, _self);
751 
752   switch (upb_filedef_syntax(self->filedef)) {
753     case UPB_SYNTAX_PROTO3: return ID2SYM(rb_intern("proto3"));
754     case UPB_SYNTAX_PROTO2: return ID2SYM(rb_intern("proto2"));
755     default: return Qnil;
756   }
757 }
758 
759 // -----------------------------------------------------------------------------
760 // FieldDescriptor.
761 // -----------------------------------------------------------------------------
762 
763 DEFINE_CLASS(FieldDescriptor, "Google::Protobuf::FieldDescriptor");
764 
FieldDescriptor_mark(void * _self)765 void FieldDescriptor_mark(void* _self) {
766   FieldDescriptor* self = _self;
767   rb_gc_mark(self->descriptor_pool);
768 }
769 
FieldDescriptor_free(void * _self)770 void FieldDescriptor_free(void* _self) {
771   xfree(_self);
772 }
773 
774 /*
775  * call-seq:
776  *     FieldDescriptor.new => field
777  *
778  * Returns a new field descriptor. Its name, type, etc. must be set before it is
779  * added to a message type.
780  */
FieldDescriptor_alloc(VALUE klass)781 VALUE FieldDescriptor_alloc(VALUE klass) {
782   FieldDescriptor* self = ALLOC(FieldDescriptor);
783   VALUE ret = TypedData_Wrap_Struct(klass, &_FieldDescriptor_type, self);
784   self->fielddef = NULL;
785   return ret;
786 }
787 
FieldDescriptor_register(VALUE module)788 void FieldDescriptor_register(VALUE module) {
789   VALUE klass = rb_define_class_under(
790       module, "FieldDescriptor", rb_cObject);
791   rb_define_alloc_func(klass, FieldDescriptor_alloc);
792   rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3);
793   rb_define_method(klass, "name", FieldDescriptor_name, 0);
794   rb_define_method(klass, "type", FieldDescriptor_type, 0);
795   rb_define_method(klass, "default", FieldDescriptor_default, 0);
796   rb_define_method(klass, "label", FieldDescriptor_label, 0);
797   rb_define_method(klass, "number", FieldDescriptor_number, 0);
798   rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
799   rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
800   rb_define_method(klass, "has?", FieldDescriptor_has, 1);
801   rb_define_method(klass, "clear", FieldDescriptor_clear, 1);
802   rb_define_method(klass, "get", FieldDescriptor_get, 1);
803   rb_define_method(klass, "set", FieldDescriptor_set, 2);
804   rb_gc_register_address(&cFieldDescriptor);
805   cFieldDescriptor = klass;
806 }
807 
808 /*
809  * call-seq:
810  *    EnumDescriptor.new(c_only_cookie, pool, ptr) => EnumDescriptor
811  *
812  * Creates a descriptor wrapper object.  May only be called from C.
813  */
FieldDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)814 VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
815                                  VALUE descriptor_pool, VALUE ptr) {
816   DEFINE_SELF(FieldDescriptor, self, _self);
817 
818   if (cookie != c_only_cookie) {
819     rb_raise(rb_eRuntimeError,
820              "Descriptor objects may not be created from Ruby.");
821   }
822 
823   self->descriptor_pool = descriptor_pool;
824   self->fielddef = (const upb_fielddef*)NUM2ULL(ptr);
825 
826   return Qnil;
827 }
828 
829 /*
830  * call-seq:
831  *     FieldDescriptor.name => name
832  *
833  * Returns the name of this field.
834  */
FieldDescriptor_name(VALUE _self)835 VALUE FieldDescriptor_name(VALUE _self) {
836   DEFINE_SELF(FieldDescriptor, self, _self);
837   return rb_str_maybe_null(upb_fielddef_name(self->fielddef));
838 }
839 
ruby_to_fieldtype(VALUE type)840 upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
841   if (TYPE(type) != T_SYMBOL) {
842     rb_raise(rb_eArgError, "Expected symbol for field type.");
843   }
844 
845 #define CONVERT(upb, ruby)                                           \
846   if (SYM2ID(type) == rb_intern( # ruby )) {                         \
847     return UPB_TYPE_ ## upb;                                         \
848   }
849 
850   CONVERT(FLOAT, float);
851   CONVERT(DOUBLE, double);
852   CONVERT(BOOL, bool);
853   CONVERT(STRING, string);
854   CONVERT(BYTES, bytes);
855   CONVERT(MESSAGE, message);
856   CONVERT(ENUM, enum);
857   CONVERT(INT32, int32);
858   CONVERT(INT64, int64);
859   CONVERT(UINT32, uint32);
860   CONVERT(UINT64, uint64);
861 
862 #undef CONVERT
863 
864   rb_raise(rb_eArgError, "Unknown field type.");
865   return 0;
866 }
867 
fieldtype_to_ruby(upb_fieldtype_t type)868 VALUE fieldtype_to_ruby(upb_fieldtype_t type) {
869   switch (type) {
870 #define CONVERT(upb, ruby)                                           \
871     case UPB_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
872     CONVERT(FLOAT, float);
873     CONVERT(DOUBLE, double);
874     CONVERT(BOOL, bool);
875     CONVERT(STRING, string);
876     CONVERT(BYTES, bytes);
877     CONVERT(MESSAGE, message);
878     CONVERT(ENUM, enum);
879     CONVERT(INT32, int32);
880     CONVERT(INT64, int64);
881     CONVERT(UINT32, uint32);
882     CONVERT(UINT64, uint64);
883 #undef CONVERT
884   }
885   return Qnil;
886 }
887 
ruby_to_descriptortype(VALUE type)888 upb_descriptortype_t ruby_to_descriptortype(VALUE type) {
889   if (TYPE(type) != T_SYMBOL) {
890     rb_raise(rb_eArgError, "Expected symbol for field type.");
891   }
892 
893 #define CONVERT(upb, ruby)                                           \
894   if (SYM2ID(type) == rb_intern( # ruby )) {                         \
895     return UPB_DESCRIPTOR_TYPE_ ## upb;                              \
896   }
897 
898   CONVERT(FLOAT, float);
899   CONVERT(DOUBLE, double);
900   CONVERT(BOOL, bool);
901   CONVERT(STRING, string);
902   CONVERT(BYTES, bytes);
903   CONVERT(MESSAGE, message);
904   CONVERT(GROUP, group);
905   CONVERT(ENUM, enum);
906   CONVERT(INT32, int32);
907   CONVERT(INT64, int64);
908   CONVERT(UINT32, uint32);
909   CONVERT(UINT64, uint64);
910   CONVERT(SINT32, sint32);
911   CONVERT(SINT64, sint64);
912   CONVERT(FIXED32, fixed32);
913   CONVERT(FIXED64, fixed64);
914   CONVERT(SFIXED32, sfixed32);
915   CONVERT(SFIXED64, sfixed64);
916 
917 #undef CONVERT
918 
919   rb_raise(rb_eArgError, "Unknown field type.");
920   return 0;
921 }
922 
descriptortype_to_ruby(upb_descriptortype_t type)923 VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
924   switch (type) {
925 #define CONVERT(upb, ruby)                                           \
926     case UPB_DESCRIPTOR_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
927     CONVERT(FLOAT, float);
928     CONVERT(DOUBLE, double);
929     CONVERT(BOOL, bool);
930     CONVERT(STRING, string);
931     CONVERT(BYTES, bytes);
932     CONVERT(MESSAGE, message);
933     CONVERT(GROUP, group);
934     CONVERT(ENUM, enum);
935     CONVERT(INT32, int32);
936     CONVERT(INT64, int64);
937     CONVERT(UINT32, uint32);
938     CONVERT(UINT64, uint64);
939     CONVERT(SINT32, sint32);
940     CONVERT(SINT64, sint64);
941     CONVERT(FIXED32, fixed32);
942     CONVERT(FIXED64, fixed64);
943     CONVERT(SFIXED32, sfixed32);
944     CONVERT(SFIXED64, sfixed64);
945 #undef CONVERT
946   }
947   return Qnil;
948 }
949 
ruby_to_label(VALUE label)950 VALUE ruby_to_label(VALUE label) {
951   upb_label_t upb_label;
952   bool converted = false;
953 
954 #define CONVERT(upb, ruby)                                           \
955   if (SYM2ID(label) == rb_intern( # ruby )) {                        \
956     upb_label = UPB_LABEL_ ## upb;                                   \
957     converted = true;                                                \
958   }
959 
960   CONVERT(OPTIONAL, optional);
961   CONVERT(REQUIRED, required);
962   CONVERT(REPEATED, repeated);
963 
964 #undef CONVERT
965 
966   if (!converted) {
967     rb_raise(rb_eArgError, "Unknown field label.");
968   }
969 
970   return upb_label;
971 }
972 
973 /*
974  * call-seq:
975  *     FieldDescriptor.type => type
976  *
977  * Returns this field's type, as a Ruby symbol, or nil if not yet set.
978  *
979  * Valid field types are:
980  *     :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
981  *     :bytes, :message.
982  */
FieldDescriptor_type(VALUE _self)983 VALUE FieldDescriptor_type(VALUE _self) {
984   DEFINE_SELF(FieldDescriptor, self, _self);
985   return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef));
986 }
987 
988 /*
989  * call-seq:
990  *     FieldDescriptor.default => default
991  *
992  * Returns this field's default, as a Ruby object, or nil if not yet set.
993  */
FieldDescriptor_default(VALUE _self)994 VALUE FieldDescriptor_default(VALUE _self) {
995   DEFINE_SELF(FieldDescriptor, self, _self);
996   return layout_get_default(self->fielddef);
997 }
998 
999 /*
1000  * call-seq:
1001  *     FieldDescriptor.label => label
1002  *
1003  * Returns this field's label (i.e., plurality), as a Ruby symbol.
1004  *
1005  * Valid field labels are:
1006  *     :optional, :repeated
1007  */
FieldDescriptor_label(VALUE _self)1008 VALUE FieldDescriptor_label(VALUE _self) {
1009   DEFINE_SELF(FieldDescriptor, self, _self);
1010   switch (upb_fielddef_label(self->fielddef)) {
1011 #define CONVERT(upb, ruby)                                           \
1012     case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby ));
1013 
1014     CONVERT(OPTIONAL, optional);
1015     CONVERT(REQUIRED, required);
1016     CONVERT(REPEATED, repeated);
1017 
1018 #undef CONVERT
1019   }
1020 
1021   return Qnil;
1022 }
1023 
1024 /*
1025  * call-seq:
1026  *     FieldDescriptor.number => number
1027  *
1028  * Returns the tag number for this field.
1029  */
FieldDescriptor_number(VALUE _self)1030 VALUE FieldDescriptor_number(VALUE _self) {
1031   DEFINE_SELF(FieldDescriptor, self, _self);
1032   return INT2NUM(upb_fielddef_number(self->fielddef));
1033 }
1034 
1035 /*
1036  * call-seq:
1037  *     FieldDescriptor.submsg_name => submsg_name
1038  *
1039  * Returns the name of the message or enum type corresponding to this field, if
1040  * it is a message or enum field (respectively), or nil otherwise. This type
1041  * name will be resolved within the context of the pool to which the containing
1042  * message type is added.
1043  */
FieldDescriptor_submsg_name(VALUE _self)1044 VALUE FieldDescriptor_submsg_name(VALUE _self) {
1045   DEFINE_SELF(FieldDescriptor, self, _self);
1046   switch (upb_fielddef_type(self->fielddef)) {
1047     case UPB_TYPE_ENUM:
1048       return rb_str_new2(
1049           upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef)));
1050     case UPB_TYPE_MESSAGE:
1051       return rb_str_new2(
1052           upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef)));
1053     default:
1054       return Qnil;
1055   }
1056 }
1057 
1058 /*
1059  * call-seq:
1060  *     FieldDescriptor.subtype => message_or_enum_descriptor
1061  *
1062  * Returns the message or enum descriptor corresponding to this field's type if
1063  * it is a message or enum field, respectively, or nil otherwise. Cannot be
1064  * called *until* the containing message type is added to a pool (and thus
1065  * resolved).
1066  */
FieldDescriptor_subtype(VALUE _self)1067 VALUE FieldDescriptor_subtype(VALUE _self) {
1068   DEFINE_SELF(FieldDescriptor, self, _self);
1069   switch (upb_fielddef_type(self->fielddef)) {
1070     case UPB_TYPE_ENUM:
1071       return get_enumdef_obj(self->descriptor_pool,
1072                              upb_fielddef_enumsubdef(self->fielddef));
1073     case UPB_TYPE_MESSAGE:
1074       return get_msgdef_obj(self->descriptor_pool,
1075                             upb_fielddef_msgsubdef(self->fielddef));
1076     default:
1077       return Qnil;
1078   }
1079 }
1080 
1081 /*
1082  * call-seq:
1083  *     FieldDescriptor.get(message) => value
1084  *
1085  * Returns the value set for this field on the given message. Raises an
1086  * exception if message is of the wrong type.
1087  */
FieldDescriptor_get(VALUE _self,VALUE msg_rb)1088 VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
1089   DEFINE_SELF(FieldDescriptor, self, _self);
1090   MessageHeader* msg;
1091   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
1092   if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
1093     rb_raise(cTypeError, "get method called on wrong message type");
1094   }
1095   return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
1096 }
1097 
1098 /*
1099  * call-seq:
1100  *     FieldDescriptor.has?(message) => boolean
1101  *
1102  * Returns whether the value is set on the given message. Raises an
1103  * exception when calling for fields that do not have presence.
1104  */
FieldDescriptor_has(VALUE _self,VALUE msg_rb)1105 VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
1106   DEFINE_SELF(FieldDescriptor, self, _self);
1107   MessageHeader* msg;
1108   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
1109   if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
1110     rb_raise(cTypeError, "has method called on wrong message type");
1111   } else if (!upb_fielddef_haspresence(self->fielddef)) {
1112     rb_raise(rb_eArgError, "does not track presence");
1113   }
1114 
1115   return layout_has(msg->descriptor->layout, Message_data(msg), self->fielddef);
1116 }
1117 
1118 /*
1119  * call-seq:
1120  *     FieldDescriptor.clear(message)
1121  *
1122  * Clears the field from the message if it's set.
1123  */
FieldDescriptor_clear(VALUE _self,VALUE msg_rb)1124 VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
1125   DEFINE_SELF(FieldDescriptor, self, _self);
1126   MessageHeader* msg;
1127   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
1128   if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
1129     rb_raise(cTypeError, "has method called on wrong message type");
1130   }
1131 
1132   layout_clear(msg->descriptor->layout, Message_data(msg), self->fielddef);
1133   return Qnil;
1134 }
1135 
1136 /*
1137  * call-seq:
1138  *     FieldDescriptor.set(message, value)
1139  *
1140  * Sets the value corresponding to this field to the given value on the given
1141  * message. Raises an exception if message is of the wrong type. Performs the
1142  * ordinary type-checks for field setting.
1143  */
FieldDescriptor_set(VALUE _self,VALUE msg_rb,VALUE value)1144 VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
1145   DEFINE_SELF(FieldDescriptor, self, _self);
1146   MessageHeader* msg;
1147   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
1148   if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
1149     rb_raise(cTypeError, "set method called on wrong message type");
1150   }
1151   layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value);
1152   return Qnil;
1153 }
1154 
1155 // -----------------------------------------------------------------------------
1156 // OneofDescriptor.
1157 // -----------------------------------------------------------------------------
1158 
1159 DEFINE_CLASS(OneofDescriptor, "Google::Protobuf::OneofDescriptor");
1160 
OneofDescriptor_mark(void * _self)1161 void OneofDescriptor_mark(void* _self) {
1162   OneofDescriptor* self = _self;
1163   rb_gc_mark(self->descriptor_pool);
1164 }
1165 
OneofDescriptor_free(void * _self)1166 void OneofDescriptor_free(void* _self) {
1167   xfree(_self);
1168 }
1169 
1170 /*
1171  * call-seq:
1172  *     OneofDescriptor.new => oneof_descriptor
1173  *
1174  * Creates a new, empty, oneof descriptor. The oneof may only be modified prior
1175  * to being added to a message descriptor which is subsequently added to a pool.
1176  */
OneofDescriptor_alloc(VALUE klass)1177 VALUE OneofDescriptor_alloc(VALUE klass) {
1178   OneofDescriptor* self = ALLOC(OneofDescriptor);
1179   VALUE ret = TypedData_Wrap_Struct(klass, &_OneofDescriptor_type, self);
1180   self->oneofdef = NULL;
1181   self->descriptor_pool = Qnil;
1182   return ret;
1183 }
1184 
OneofDescriptor_register(VALUE module)1185 void OneofDescriptor_register(VALUE module) {
1186   VALUE klass = rb_define_class_under(
1187       module, "OneofDescriptor", rb_cObject);
1188   rb_define_alloc_func(klass, OneofDescriptor_alloc);
1189   rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3);
1190   rb_define_method(klass, "name", OneofDescriptor_name, 0);
1191   rb_define_method(klass, "each", OneofDescriptor_each, 0);
1192   rb_include_module(klass, rb_mEnumerable);
1193   rb_gc_register_address(&cOneofDescriptor);
1194   cOneofDescriptor = klass;
1195 }
1196 
1197 /*
1198  * call-seq:
1199  *    OneofDescriptor.new(c_only_cookie, pool, ptr) => OneofDescriptor
1200  *
1201  * Creates a descriptor wrapper object.  May only be called from C.
1202  */
OneofDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)1203 VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
1204                                  VALUE descriptor_pool, VALUE ptr) {
1205   DEFINE_SELF(OneofDescriptor, self, _self);
1206 
1207   if (cookie != c_only_cookie) {
1208     rb_raise(rb_eRuntimeError,
1209              "Descriptor objects may not be created from Ruby.");
1210   }
1211 
1212   self->descriptor_pool = descriptor_pool;
1213   self->oneofdef = (const upb_oneofdef*)NUM2ULL(ptr);
1214 
1215   return Qnil;
1216 }
1217 
1218 /*
1219  * call-seq:
1220  *     OneofDescriptor.name => name
1221  *
1222  * Returns the name of this oneof.
1223  */
OneofDescriptor_name(VALUE _self)1224 VALUE OneofDescriptor_name(VALUE _self) {
1225   DEFINE_SELF(OneofDescriptor, self, _self);
1226   return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
1227 }
1228 
1229 /*
1230  * call-seq:
1231  *     OneofDescriptor.each(&block) => nil
1232  *
1233  * Iterates through fields in this oneof, yielding to the block on each one.
1234  */
OneofDescriptor_each(VALUE _self)1235 VALUE OneofDescriptor_each(VALUE _self) {
1236   DEFINE_SELF(OneofDescriptor, self, _self);
1237   upb_oneof_iter it;
1238   for (upb_oneof_begin(&it, self->oneofdef);
1239        !upb_oneof_done(&it);
1240        upb_oneof_next(&it)) {
1241     const upb_fielddef* f = upb_oneof_iter_field(&it);
1242     VALUE obj = get_fielddef_obj(self->descriptor_pool, f);
1243     rb_yield(obj);
1244   }
1245   return Qnil;
1246 }
1247 
1248 // -----------------------------------------------------------------------------
1249 // EnumDescriptor.
1250 // -----------------------------------------------------------------------------
1251 
1252 DEFINE_CLASS(EnumDescriptor, "Google::Protobuf::EnumDescriptor");
1253 
EnumDescriptor_mark(void * _self)1254 void EnumDescriptor_mark(void* _self) {
1255   EnumDescriptor* self = _self;
1256   rb_gc_mark(self->module);
1257   rb_gc_mark(self->descriptor_pool);
1258 }
1259 
EnumDescriptor_free(void * _self)1260 void EnumDescriptor_free(void* _self) {
1261   xfree(_self);
1262 }
1263 
EnumDescriptor_alloc(VALUE klass)1264 VALUE EnumDescriptor_alloc(VALUE klass) {
1265   EnumDescriptor* self = ALLOC(EnumDescriptor);
1266   VALUE ret = TypedData_Wrap_Struct(klass, &_EnumDescriptor_type, self);
1267   self->enumdef = NULL;
1268   self->module = Qnil;
1269   self->descriptor_pool = Qnil;
1270   return ret;
1271 }
1272 
1273 /*
1274  * call-seq:
1275  *    EnumDescriptor.new(c_only_cookie, ptr) => EnumDescriptor
1276  *
1277  * Creates a descriptor wrapper object.  May only be called from C.
1278  */
EnumDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)1279 VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
1280                                 VALUE descriptor_pool, VALUE ptr) {
1281   DEFINE_SELF(EnumDescriptor, self, _self);
1282 
1283   if (cookie != c_only_cookie) {
1284     rb_raise(rb_eRuntimeError,
1285              "Descriptor objects may not be created from Ruby.");
1286   }
1287 
1288   self->descriptor_pool = descriptor_pool;
1289   self->enumdef = (const upb_enumdef*)NUM2ULL(ptr);
1290 
1291   return Qnil;
1292 }
1293 
EnumDescriptor_register(VALUE module)1294 void EnumDescriptor_register(VALUE module) {
1295   VALUE klass = rb_define_class_under(
1296       module, "EnumDescriptor", rb_cObject);
1297   rb_define_alloc_func(klass, EnumDescriptor_alloc);
1298   rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3);
1299   rb_define_method(klass, "name", EnumDescriptor_name, 0);
1300   rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
1301   rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
1302   rb_define_method(klass, "each", EnumDescriptor_each, 0);
1303   rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
1304   rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0);
1305   rb_include_module(klass, rb_mEnumerable);
1306   rb_gc_register_address(&cEnumDescriptor);
1307   cEnumDescriptor = klass;
1308 }
1309 
1310 /*
1311  * call-seq:
1312  *    EnumDescriptor.file_descriptor
1313  *
1314  * Returns the FileDescriptor object this enum belongs to.
1315  */
EnumDescriptor_file_descriptor(VALUE _self)1316 VALUE EnumDescriptor_file_descriptor(VALUE _self) {
1317   DEFINE_SELF(EnumDescriptor, self, _self);
1318   return get_filedef_obj(self->descriptor_pool,
1319                          upb_enumdef_file(self->enumdef));
1320 }
1321 
1322 /*
1323  * call-seq:
1324  *     EnumDescriptor.name => name
1325  *
1326  * Returns the name of this enum type.
1327  */
EnumDescriptor_name(VALUE _self)1328 VALUE EnumDescriptor_name(VALUE _self) {
1329   DEFINE_SELF(EnumDescriptor, self, _self);
1330   return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef));
1331 }
1332 
1333 /*
1334  * call-seq:
1335  *     EnumDescriptor.lookup_name(name) => value
1336  *
1337  * Returns the numeric value corresponding to the given key name (as a Ruby
1338  * symbol), or nil if none.
1339  */
EnumDescriptor_lookup_name(VALUE _self,VALUE name)1340 VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
1341   DEFINE_SELF(EnumDescriptor, self, _self);
1342   const char* name_str= rb_id2name(SYM2ID(name));
1343   int32_t val = 0;
1344   if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) {
1345     return INT2NUM(val);
1346   } else {
1347     return Qnil;
1348   }
1349 }
1350 
1351 /*
1352  * call-seq:
1353  *     EnumDescriptor.lookup_value(name) => value
1354  *
1355  * Returns the key name (as a Ruby symbol) corresponding to the integer value,
1356  * or nil if none.
1357  */
EnumDescriptor_lookup_value(VALUE _self,VALUE number)1358 VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
1359   DEFINE_SELF(EnumDescriptor, self, _self);
1360   int32_t val = NUM2INT(number);
1361   const char* name = upb_enumdef_iton(self->enumdef, val);
1362   if (name != NULL) {
1363     return ID2SYM(rb_intern(name));
1364   } else {
1365     return Qnil;
1366   }
1367 }
1368 
1369 /*
1370  * call-seq:
1371  *     EnumDescriptor.each(&block)
1372  *
1373  * Iterates over key => value mappings in this enum's definition, yielding to
1374  * the block with (key, value) arguments for each one.
1375  */
EnumDescriptor_each(VALUE _self)1376 VALUE EnumDescriptor_each(VALUE _self) {
1377   DEFINE_SELF(EnumDescriptor, self, _self);
1378 
1379   upb_enum_iter it;
1380   for (upb_enum_begin(&it, self->enumdef);
1381        !upb_enum_done(&it);
1382        upb_enum_next(&it)) {
1383     VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it)));
1384     VALUE number = INT2NUM(upb_enum_iter_number(&it));
1385     rb_yield_values(2, key, number);
1386   }
1387 
1388   return Qnil;
1389 }
1390 
1391 /*
1392  * call-seq:
1393  *     EnumDescriptor.enummodule => module
1394  *
1395  * Returns the Ruby module corresponding to this enum type.
1396  */
EnumDescriptor_enummodule(VALUE _self)1397 VALUE EnumDescriptor_enummodule(VALUE _self) {
1398   DEFINE_SELF(EnumDescriptor, self, _self);
1399   if (self->module == Qnil) {
1400     self->module = build_module_from_enumdesc(_self);
1401   }
1402   return self->module;
1403 }
1404 
1405 // -----------------------------------------------------------------------------
1406 // MessageBuilderContext.
1407 // -----------------------------------------------------------------------------
1408 
1409 DEFINE_CLASS(MessageBuilderContext,
1410     "Google::Protobuf::Internal::MessageBuilderContext");
1411 
MessageBuilderContext_mark(void * _self)1412 void MessageBuilderContext_mark(void* _self) {
1413   MessageBuilderContext* self = _self;
1414   rb_gc_mark(self->file_builder);
1415 }
1416 
MessageBuilderContext_free(void * _self)1417 void MessageBuilderContext_free(void* _self) {
1418   MessageBuilderContext* self = _self;
1419   xfree(self);
1420 }
1421 
MessageBuilderContext_alloc(VALUE klass)1422 VALUE MessageBuilderContext_alloc(VALUE klass) {
1423   MessageBuilderContext* self = ALLOC(MessageBuilderContext);
1424   VALUE ret = TypedData_Wrap_Struct(
1425       klass, &_MessageBuilderContext_type, self);
1426   self->file_builder = Qnil;
1427   return ret;
1428 }
1429 
MessageBuilderContext_register(VALUE module)1430 void MessageBuilderContext_register(VALUE module) {
1431   VALUE klass = rb_define_class_under(
1432       module, "MessageBuilderContext", rb_cObject);
1433   rb_define_alloc_func(klass, MessageBuilderContext_alloc);
1434   rb_define_method(klass, "initialize",
1435                    MessageBuilderContext_initialize, 2);
1436   rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
1437   rb_define_method(klass, "proto3_optional", MessageBuilderContext_proto3_optional, -1);
1438   rb_define_method(klass, "required", MessageBuilderContext_required, -1);
1439   rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
1440   rb_define_method(klass, "map", MessageBuilderContext_map, -1);
1441   rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
1442   rb_gc_register_address(&cMessageBuilderContext);
1443   cMessageBuilderContext = klass;
1444 }
1445 
1446 /*
1447  * call-seq:
1448  *     MessageBuilderContext.new(file_builder, name) => context
1449  *
1450  * Create a new message builder context around the given message descriptor and
1451  * builder context. This class is intended to serve as a DSL context to be used
1452  * with #instance_eval.
1453  */
MessageBuilderContext_initialize(VALUE _self,VALUE _file_builder,VALUE name)1454 VALUE MessageBuilderContext_initialize(VALUE _self,
1455                                        VALUE _file_builder,
1456                                        VALUE name) {
1457   DEFINE_SELF(MessageBuilderContext, self, _self);
1458   FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
1459   google_protobuf_FileDescriptorProto* file_proto = file_builder->file_proto;
1460 
1461   self->file_builder = _file_builder;
1462   self->msg_proto = google_protobuf_FileDescriptorProto_add_message_type(
1463       file_proto, file_builder->arena);
1464 
1465   google_protobuf_DescriptorProto_set_name(
1466       self->msg_proto, FileBuilderContext_strdup(_file_builder, name));
1467 
1468   return Qnil;
1469 }
1470 
msgdef_add_field(VALUE msgbuilder_rb,upb_label_t label,VALUE name,VALUE type,VALUE number,VALUE type_class,VALUE options,int oneof_index,bool proto3_optional)1471 static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
1472                              VALUE type, VALUE number, VALUE type_class,
1473                              VALUE options, int oneof_index,
1474                              bool proto3_optional) {
1475   DEFINE_SELF(MessageBuilderContext, self, msgbuilder_rb);
1476   FileBuilderContext* file_context =
1477       ruby_to_FileBuilderContext(self->file_builder);
1478   google_protobuf_FieldDescriptorProto* field_proto;
1479   VALUE name_str;
1480 
1481   field_proto = google_protobuf_DescriptorProto_add_field(self->msg_proto,
1482                                                           file_context->arena);
1483 
1484   Check_Type(name, T_SYMBOL);
1485   name_str = rb_id2str(SYM2ID(name));
1486 
1487   google_protobuf_FieldDescriptorProto_set_name(
1488       field_proto, FileBuilderContext_strdup(self->file_builder, name_str));
1489   google_protobuf_FieldDescriptorProto_set_number(field_proto, NUM2INT(number));
1490   google_protobuf_FieldDescriptorProto_set_label(field_proto, (int)label);
1491   google_protobuf_FieldDescriptorProto_set_type(
1492       field_proto, (int)ruby_to_descriptortype(type));
1493 
1494   if (proto3_optional) {
1495     google_protobuf_FieldDescriptorProto_set_proto3_optional(field_proto, true);
1496   }
1497 
1498   if (type_class != Qnil) {
1499     Check_Type(type_class, T_STRING);
1500 
1501     // Make it an absolute type name by prepending a dot.
1502     type_class = rb_str_append(rb_str_new2("."), type_class);
1503     google_protobuf_FieldDescriptorProto_set_type_name(
1504         field_proto, FileBuilderContext_strdup(self->file_builder, type_class));
1505   }
1506 
1507   if (options != Qnil) {
1508     Check_Type(options, T_HASH);
1509 
1510     if (rb_funcall(options, rb_intern("key?"), 1,
1511                    ID2SYM(rb_intern("default"))) == Qtrue) {
1512       VALUE default_value =
1513           rb_hash_lookup(options, ID2SYM(rb_intern("default")));
1514 
1515       /* Call #to_s since all defaults are strings in the descriptor. */
1516       default_value = rb_funcall(default_value, rb_intern("to_s"), 0);
1517 
1518       google_protobuf_FieldDescriptorProto_set_default_value(
1519           field_proto,
1520           FileBuilderContext_strdup(self->file_builder, default_value));
1521     }
1522   }
1523 
1524   if (oneof_index >= 0) {
1525     google_protobuf_FieldDescriptorProto_set_oneof_index(field_proto,
1526                                                          oneof_index);
1527   }
1528 }
1529 
make_mapentry(VALUE _message_builder,VALUE types,int argc,VALUE * argv)1530 static VALUE make_mapentry(VALUE _message_builder, VALUE types, int argc,
1531                            VALUE* argv) {
1532   DEFINE_SELF(MessageBuilderContext, message_builder, _message_builder);
1533   VALUE type_class = rb_ary_entry(types, 2);
1534   FileBuilderContext* file_context =
1535       ruby_to_FileBuilderContext(message_builder->file_builder);
1536   google_protobuf_MessageOptions* options =
1537       google_protobuf_DescriptorProto_mutable_options(
1538           message_builder->msg_proto, file_context->arena);
1539 
1540   google_protobuf_MessageOptions_set_map_entry(options, true);
1541 
1542   // optional <type> key = 1;
1543   rb_funcall(_message_builder, rb_intern("optional"), 3,
1544              ID2SYM(rb_intern("key")), rb_ary_entry(types, 0), INT2NUM(1));
1545 
1546   // optional <type> value = 2;
1547   if (type_class == Qnil) {
1548     rb_funcall(_message_builder, rb_intern("optional"), 3,
1549                ID2SYM(rb_intern("value")), rb_ary_entry(types, 1), INT2NUM(2));
1550   } else {
1551     rb_funcall(_message_builder, rb_intern("optional"), 4,
1552                ID2SYM(rb_intern("value")), rb_ary_entry(types, 1), INT2NUM(2),
1553                type_class);
1554   }
1555 
1556   return Qnil;
1557 }
1558 
1559 /*
1560  * call-seq:
1561  *     MessageBuilderContext.optional(name, type, number, type_class = nil,
1562  *                                    options = nil)
1563  *
1564  * Defines a new optional field on this message type with the given type, tag
1565  * number, and type class (for message and enum fields). The type must be a Ruby
1566  * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
1567  * string, if present (as accepted by FieldDescriptor#submsg_name=).
1568  */
MessageBuilderContext_optional(int argc,VALUE * argv,VALUE _self)1569 VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
1570   VALUE name, type, number;
1571   VALUE type_class, options = Qnil;
1572 
1573   rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1574 
1575   // Allow passing (name, type, number, options) or
1576   // (name, type, number, type_class, options)
1577   if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1578     options = type_class;
1579     type_class = Qnil;
1580   }
1581 
1582   msgdef_add_field(_self, UPB_LABEL_OPTIONAL, name, type, number, type_class,
1583                    options, -1, false);
1584 
1585   return Qnil;
1586 }
1587 
1588 /*
1589  * call-seq:
1590  *     MessageBuilderContext.proto3_optional(name, type, number,
1591  *                                           type_class = nil, options = nil)
1592  *
1593  * Defines a true proto3 optional field (that tracks presence) on this message
1594  * type with the given type, tag number, and type class (for message and enum
1595  * fields). The type must be a Ruby symbol (as accepted by
1596  * FieldDescriptor#type=) and the type_class must be a string, if present (as
1597  * accepted by FieldDescriptor#submsg_name=).
1598  */
MessageBuilderContext_proto3_optional(int argc,VALUE * argv,VALUE _self)1599 VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv,
1600                                             VALUE _self) {
1601   VALUE name, type, number;
1602   VALUE type_class, options = Qnil;
1603 
1604   rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1605 
1606   // Allow passing (name, type, number, options) or
1607   // (name, type, number, type_class, options)
1608   if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1609     options = type_class;
1610     type_class = Qnil;
1611   }
1612 
1613   msgdef_add_field(_self, UPB_LABEL_OPTIONAL, name, type, number, type_class,
1614                    options, -1, true);
1615 
1616   return Qnil;
1617 }
1618 
1619 /*
1620  * call-seq:
1621  *     MessageBuilderContext.required(name, type, number, type_class = nil,
1622  *                                    options = nil)
1623  *
1624  * Defines a new required field on this message type with the given type, tag
1625  * number, and type class (for message and enum fields). The type must be a Ruby
1626  * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
1627  * string, if present (as accepted by FieldDescriptor#submsg_name=).
1628  *
1629  * Proto3 does not have required fields, but this method exists for
1630  * completeness. Any attempt to add a message type with required fields to a
1631  * pool will currently result in an error.
1632  */
MessageBuilderContext_required(int argc,VALUE * argv,VALUE _self)1633 VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
1634   VALUE name, type, number;
1635   VALUE type_class, options = Qnil;
1636 
1637   rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1638 
1639   // Allow passing (name, type, number, options) or
1640   // (name, type, number, type_class, options)
1641   if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1642     options = type_class;
1643     type_class = Qnil;
1644   }
1645 
1646   msgdef_add_field(_self, UPB_LABEL_REQUIRED, name, type, number, type_class,
1647                    options, -1, false);
1648 
1649   return Qnil;
1650 }
1651 
1652 /*
1653  * call-seq:
1654  *     MessageBuilderContext.repeated(name, type, number, type_class = nil)
1655  *
1656  * Defines a new repeated field on this message type with the given type, tag
1657  * number, and type class (for message and enum fields). The type must be a Ruby
1658  * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
1659  * string, if present (as accepted by FieldDescriptor#submsg_name=).
1660  */
MessageBuilderContext_repeated(int argc,VALUE * argv,VALUE _self)1661 VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
1662   VALUE name, type, number, type_class;
1663 
1664   if (argc < 3) {
1665     rb_raise(rb_eArgError, "Expected at least 3 arguments.");
1666   }
1667   name = argv[0];
1668   type = argv[1];
1669   number = argv[2];
1670   type_class = (argc > 3) ? argv[3] : Qnil;
1671 
1672   msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
1673                    Qnil, -1, false);
1674 
1675   return Qnil;
1676 }
1677 
1678 /*
1679  * call-seq:
1680  *     MessageBuilderContext.map(name, key_type, value_type, number,
1681  *                               value_type_class = nil)
1682  *
1683  * Defines a new map field on this message type with the given key and value
1684  * types, tag number, and type class (for message and enum value types). The key
1685  * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
1686  * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
1687  * type_class must be a string, if present (as accepted by
1688  * FieldDescriptor#submsg_name=).
1689  */
MessageBuilderContext_map(int argc,VALUE * argv,VALUE _self)1690 VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
1691   DEFINE_SELF(MessageBuilderContext, self, _self);
1692   VALUE name, key_type, value_type, number, type_class;
1693   VALUE mapentry_desc_name;
1694   FileBuilderContext* file_builder;
1695   upb_strview msg_name;
1696 
1697   if (argc < 4) {
1698     rb_raise(rb_eArgError, "Expected at least 4 arguments.");
1699   }
1700   name = argv[0];
1701   key_type = argv[1];
1702   value_type = argv[2];
1703   number = argv[3];
1704   type_class = (argc > 4) ? argv[4] : Qnil;
1705 
1706   // Validate the key type. We can't accept enums, messages, or floats/doubles
1707   // as map keys. (We exclude these explicitly, and the field-descriptor setter
1708   // below then ensures that the type is one of the remaining valid options.)
1709   if (SYM2ID(key_type) == rb_intern("float") ||
1710       SYM2ID(key_type) == rb_intern("double") ||
1711       SYM2ID(key_type) == rb_intern("enum") ||
1712       SYM2ID(key_type) == rb_intern("message")) {
1713     rb_raise(rb_eArgError,
1714              "Cannot add a map field with a float, double, enum, or message "
1715              "type.");
1716   }
1717 
1718   file_builder = ruby_to_FileBuilderContext(self->file_builder);
1719 
1720   // TODO(haberman): remove this restriction, maps are supported in proto2.
1721   if (upb_strview_eql(
1722           google_protobuf_FileDescriptorProto_syntax(file_builder->file_proto),
1723           upb_strview_makez("proto2"))) {
1724     rb_raise(rb_eArgError,
1725              "Cannot add a native map field using proto2 syntax.");
1726   }
1727 
1728   // Create a new message descriptor for the map entry message, and create a
1729   // repeated submessage field here with that type.
1730   msg_name = google_protobuf_DescriptorProto_name(self->msg_proto);
1731   mapentry_desc_name = rb_str_new(msg_name.data, msg_name.size);
1732   mapentry_desc_name = rb_str_cat2(mapentry_desc_name, "_MapEntry_");
1733   mapentry_desc_name =
1734       rb_str_cat2(mapentry_desc_name, rb_id2name(SYM2ID(name)));
1735 
1736   {
1737     // message <msgname>_MapEntry_ { /* ... */ }
1738     VALUE args[1] = {mapentry_desc_name};
1739     VALUE types = rb_ary_new3(3, key_type, value_type, type_class);
1740     rb_block_call(self->file_builder, rb_intern("add_message"), 1, args,
1741                   make_mapentry, types);
1742   }
1743 
1744   // If this file is in a package, we need to qualify the map entry type.
1745   if (google_protobuf_FileDescriptorProto_has_package(file_builder->file_proto)) {
1746     upb_strview package_view =
1747         google_protobuf_FileDescriptorProto_package(file_builder->file_proto);
1748     VALUE package = rb_str_new(package_view.data, package_view.size);
1749     package = rb_str_cat2(package, ".");
1750     mapentry_desc_name = rb_str_concat(package, mapentry_desc_name);
1751   }
1752 
1753   // repeated MapEntry <name> = <number>;
1754   rb_funcall(_self, rb_intern("repeated"), 4, name,
1755              ID2SYM(rb_intern("message")), number, mapentry_desc_name);
1756 
1757   return Qnil;
1758 }
1759 
1760 /*
1761  * call-seq:
1762  *     MessageBuilderContext.oneof(name, &block) => nil
1763  *
1764  * Creates a new OneofDescriptor with the given name, creates a
1765  * OneofBuilderContext attached to that OneofDescriptor, evaluates the given
1766  * block in the context of that OneofBuilderContext with #instance_eval, and
1767  * then adds the oneof to the message.
1768  *
1769  * This is the recommended, idiomatic way to build oneof definitions.
1770  */
MessageBuilderContext_oneof(VALUE _self,VALUE name)1771 VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
1772   DEFINE_SELF(MessageBuilderContext, self, _self);
1773   size_t oneof_count;
1774   FileBuilderContext* file_context =
1775       ruby_to_FileBuilderContext(self->file_builder);
1776   google_protobuf_OneofDescriptorProto* oneof_proto;
1777 
1778   // Existing oneof_count becomes oneof_index.
1779   google_protobuf_DescriptorProto_oneof_decl(self->msg_proto, &oneof_count);
1780 
1781   // Create oneof_proto and set its name.
1782   oneof_proto = google_protobuf_DescriptorProto_add_oneof_decl(
1783       self->msg_proto, file_context->arena);
1784   google_protobuf_OneofDescriptorProto_set_name(
1785       oneof_proto, FileBuilderContext_strdup_sym(self->file_builder, name));
1786 
1787   // Evaluate the block with the builder as argument.
1788   {
1789     VALUE args[2] = { INT2NUM(oneof_count), _self };
1790     VALUE ctx = rb_class_new_instance(2, args, cOneofBuilderContext);
1791     VALUE block = rb_block_proc();
1792     rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
1793   }
1794 
1795   return Qnil;
1796 }
1797 
MessageBuilderContext_add_synthetic_oneofs(VALUE _self)1798 void MessageBuilderContext_add_synthetic_oneofs(VALUE _self) {
1799   DEFINE_SELF(MessageBuilderContext, self, _self);
1800   FileBuilderContext* file_context =
1801       ruby_to_FileBuilderContext(self->file_builder);
1802   size_t field_count, oneof_count;
1803   google_protobuf_FieldDescriptorProto** fields =
1804       google_protobuf_DescriptorProto_mutable_field(self->msg_proto, &field_count);
1805   const google_protobuf_OneofDescriptorProto*const* oneofs =
1806       google_protobuf_DescriptorProto_oneof_decl(self->msg_proto, &oneof_count);
1807   VALUE names = rb_hash_new();
1808   VALUE underscore = rb_str_new2("_");
1809   size_t i;
1810 
1811   // We have to build a set of all names, to ensure that synthetic oneofs are
1812   // not creating conflicts.
1813   for (i = 0; i < field_count; i++) {
1814     upb_strview name = google_protobuf_FieldDescriptorProto_name(fields[i]);
1815     rb_hash_aset(names, rb_str_new(name.data, name.size), Qtrue);
1816   }
1817   for (i = 0; i < oneof_count; i++) {
1818     upb_strview name = google_protobuf_OneofDescriptorProto_name(oneofs[i]);
1819     rb_hash_aset(names, rb_str_new(name.data, name.size), Qtrue);
1820   }
1821 
1822   for (i = 0; i < field_count; i++) {
1823     google_protobuf_OneofDescriptorProto* oneof_proto;
1824     VALUE oneof_name;
1825     upb_strview field_name;
1826 
1827     if (!google_protobuf_FieldDescriptorProto_proto3_optional(fields[i])) {
1828       continue;
1829     }
1830 
1831     // Prepend '_' until we are no longer conflicting.
1832     field_name = google_protobuf_FieldDescriptorProto_name(fields[i]);
1833     oneof_name = rb_str_new(field_name.data, field_name.size);
1834     while (rb_hash_lookup(names, oneof_name) != Qnil) {
1835       oneof_name = rb_str_plus(underscore, oneof_name);
1836     }
1837 
1838     rb_hash_aset(names, oneof_name, Qtrue);
1839     google_protobuf_FieldDescriptorProto_set_oneof_index(fields[i],
1840                                                          oneof_count++);
1841     oneof_proto = google_protobuf_DescriptorProto_add_oneof_decl(
1842         self->msg_proto, file_context->arena);
1843     google_protobuf_OneofDescriptorProto_set_name(
1844         oneof_proto, FileBuilderContext_strdup(self->file_builder, oneof_name));
1845   }
1846 }
1847 
1848 // -----------------------------------------------------------------------------
1849 // OneofBuilderContext.
1850 // -----------------------------------------------------------------------------
1851 
1852 DEFINE_CLASS(OneofBuilderContext,
1853     "Google::Protobuf::Internal::OneofBuilderContext");
1854 
OneofBuilderContext_mark(void * _self)1855 void OneofBuilderContext_mark(void* _self) {
1856   OneofBuilderContext* self = _self;
1857   rb_gc_mark(self->message_builder);
1858 }
1859 
OneofBuilderContext_free(void * _self)1860 void OneofBuilderContext_free(void* _self) {
1861   xfree(_self);
1862 }
1863 
OneofBuilderContext_alloc(VALUE klass)1864 VALUE OneofBuilderContext_alloc(VALUE klass) {
1865   OneofBuilderContext* self = ALLOC(OneofBuilderContext);
1866   VALUE ret = TypedData_Wrap_Struct(
1867       klass, &_OneofBuilderContext_type, self);
1868   self->oneof_index = 0;
1869   self->message_builder = Qnil;
1870   return ret;
1871 }
1872 
OneofBuilderContext_register(VALUE module)1873 void OneofBuilderContext_register(VALUE module) {
1874   VALUE klass = rb_define_class_under(
1875       module, "OneofBuilderContext", rb_cObject);
1876   rb_define_alloc_func(klass, OneofBuilderContext_alloc);
1877   rb_define_method(klass, "initialize",
1878                    OneofBuilderContext_initialize, 2);
1879   rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
1880   rb_gc_register_address(&cOneofBuilderContext);
1881   cOneofBuilderContext = klass;
1882 }
1883 
1884 /*
1885  * call-seq:
1886  *     OneofBuilderContext.new(oneof_index, message_builder) => context
1887  *
1888  * Create a new oneof builder context around the given oneof descriptor and
1889  * builder context. This class is intended to serve as a DSL context to be used
1890  * with #instance_eval.
1891  */
OneofBuilderContext_initialize(VALUE _self,VALUE oneof_index,VALUE message_builder)1892 VALUE OneofBuilderContext_initialize(VALUE _self,
1893                                      VALUE oneof_index,
1894                                      VALUE message_builder) {
1895   DEFINE_SELF(OneofBuilderContext, self, _self);
1896   self->oneof_index = NUM2INT(oneof_index);
1897   self->message_builder = message_builder;
1898   return Qnil;
1899 }
1900 
1901 /*
1902  * call-seq:
1903  *     OneofBuilderContext.optional(name, type, number, type_class = nil,
1904  *                                  default_value = nil)
1905  *
1906  * Defines a new optional field in this oneof with the given type, tag number,
1907  * and type class (for message and enum fields). The type must be a Ruby symbol
1908  * (as accepted by FieldDescriptor#type=) and the type_class must be a string,
1909  * if present (as accepted by FieldDescriptor#submsg_name=).
1910  */
OneofBuilderContext_optional(int argc,VALUE * argv,VALUE _self)1911 VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
1912   DEFINE_SELF(OneofBuilderContext, self, _self);
1913   VALUE name, type, number;
1914   VALUE type_class, options = Qnil;
1915 
1916   rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1917 
1918   msgdef_add_field(self->message_builder, UPB_LABEL_OPTIONAL, name, type,
1919                    number, type_class, options, self->oneof_index, false);
1920 
1921   return Qnil;
1922 }
1923 
1924 // -----------------------------------------------------------------------------
1925 // EnumBuilderContext.
1926 // -----------------------------------------------------------------------------
1927 
1928 DEFINE_CLASS(EnumBuilderContext,
1929     "Google::Protobuf::Internal::EnumBuilderContext");
1930 
EnumBuilderContext_mark(void * _self)1931 void EnumBuilderContext_mark(void* _self) {
1932   EnumBuilderContext* self = _self;
1933   rb_gc_mark(self->file_builder);
1934 }
1935 
EnumBuilderContext_free(void * _self)1936 void EnumBuilderContext_free(void* _self) {
1937   xfree(_self);
1938 }
1939 
EnumBuilderContext_alloc(VALUE klass)1940 VALUE EnumBuilderContext_alloc(VALUE klass) {
1941   EnumBuilderContext* self = ALLOC(EnumBuilderContext);
1942   VALUE ret = TypedData_Wrap_Struct(
1943       klass, &_EnumBuilderContext_type, self);
1944   self->enum_proto = NULL;
1945   self->file_builder = Qnil;
1946   return ret;
1947 }
1948 
EnumBuilderContext_register(VALUE module)1949 void EnumBuilderContext_register(VALUE module) {
1950   VALUE klass = rb_define_class_under(
1951       module, "EnumBuilderContext", rb_cObject);
1952   rb_define_alloc_func(klass, EnumBuilderContext_alloc);
1953   rb_define_method(klass, "initialize", EnumBuilderContext_initialize, 2);
1954   rb_define_method(klass, "value", EnumBuilderContext_value, 2);
1955   rb_gc_register_address(&cEnumBuilderContext);
1956   cEnumBuilderContext = klass;
1957 }
1958 
1959 /*
1960  * call-seq:
1961  *     EnumBuilderContext.new(file_builder) => context
1962  *
1963  * Create a new builder context around the given enum descriptor. This class is
1964  * intended to serve as a DSL context to be used with #instance_eval.
1965  */
EnumBuilderContext_initialize(VALUE _self,VALUE _file_builder,VALUE name)1966 VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
1967                                     VALUE name) {
1968   DEFINE_SELF(EnumBuilderContext, self, _self);
1969   FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
1970   google_protobuf_FileDescriptorProto* file_proto = file_builder->file_proto;
1971 
1972   self->file_builder = _file_builder;
1973   self->enum_proto = google_protobuf_FileDescriptorProto_add_enum_type(
1974       file_proto, file_builder->arena);
1975 
1976   google_protobuf_EnumDescriptorProto_set_name(
1977       self->enum_proto, FileBuilderContext_strdup(_file_builder, name));
1978 
1979   return Qnil;
1980 }
1981 
1982 /*
1983  * call-seq:
1984  *     EnumBuilder.add_value(name, number)
1985  *
1986  * Adds the given name => number mapping to the enum type. Name must be a Ruby
1987  * symbol.
1988  */
EnumBuilderContext_value(VALUE _self,VALUE name,VALUE number)1989 VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
1990   DEFINE_SELF(EnumBuilderContext, self, _self);
1991   FileBuilderContext* file_builder =
1992       ruby_to_FileBuilderContext(self->file_builder);
1993   google_protobuf_EnumValueDescriptorProto* enum_value;
1994 
1995   enum_value = google_protobuf_EnumDescriptorProto_add_value(
1996       self->enum_proto, file_builder->arena);
1997 
1998   google_protobuf_EnumValueDescriptorProto_set_name(
1999       enum_value, FileBuilderContext_strdup_sym(self->file_builder, name));
2000   google_protobuf_EnumValueDescriptorProto_set_number(enum_value,
2001                                                       NUM2INT(number));
2002 
2003   return Qnil;
2004 }
2005 
2006 
2007 // -----------------------------------------------------------------------------
2008 // FileBuilderContext.
2009 // -----------------------------------------------------------------------------
2010 
2011 DEFINE_CLASS(FileBuilderContext,
2012              "Google::Protobuf::Internal::FileBuilderContext");
2013 
FileBuilderContext_mark(void * _self)2014 void FileBuilderContext_mark(void* _self) {
2015   FileBuilderContext* self = _self;
2016   rb_gc_mark(self->descriptor_pool);
2017 }
2018 
FileBuilderContext_free(void * _self)2019 void FileBuilderContext_free(void* _self) {
2020   FileBuilderContext* self = _self;
2021   upb_arena_free(self->arena);
2022   xfree(self);
2023 }
2024 
FileBuilderContext_strdup2(VALUE _self,const char * str)2025 upb_strview FileBuilderContext_strdup2(VALUE _self, const char *str) {
2026   DEFINE_SELF(FileBuilderContext, self, _self);
2027   upb_strview ret;
2028   char *data;
2029 
2030   ret.size = strlen(str);
2031   data = upb_malloc(upb_arena_alloc(self->arena), ret.size + 1);
2032   ret.data = data;
2033   memcpy(data, str, ret.size);
2034   /* Null-terminate required by rewrite_enum_defaults() above. */
2035   data[ret.size] = '\0';
2036   return ret;
2037 }
2038 
FileBuilderContext_strdup(VALUE _self,VALUE rb_str)2039 upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str) {
2040   return FileBuilderContext_strdup2(_self, get_str(rb_str));
2041 }
2042 
FileBuilderContext_strdup_sym(VALUE _self,VALUE rb_sym)2043 upb_strview FileBuilderContext_strdup_sym(VALUE _self, VALUE rb_sym) {
2044   Check_Type(rb_sym, T_SYMBOL);
2045   return FileBuilderContext_strdup(_self, rb_id2str(SYM2ID(rb_sym)));
2046 }
2047 
FileBuilderContext_alloc(VALUE klass)2048 VALUE FileBuilderContext_alloc(VALUE klass) {
2049   FileBuilderContext* self = ALLOC(FileBuilderContext);
2050   VALUE ret = TypedData_Wrap_Struct(klass, &_FileBuilderContext_type, self);
2051   self->arena = upb_arena_new();
2052   self->file_proto = google_protobuf_FileDescriptorProto_new(self->arena);
2053   self->descriptor_pool = Qnil;
2054   return ret;
2055 }
2056 
FileBuilderContext_register(VALUE module)2057 void FileBuilderContext_register(VALUE module) {
2058   VALUE klass = rb_define_class_under(module, "FileBuilderContext", rb_cObject);
2059   rb_define_alloc_func(klass, FileBuilderContext_alloc);
2060   rb_define_method(klass, "initialize", FileBuilderContext_initialize, 3);
2061   rb_define_method(klass, "add_message", FileBuilderContext_add_message, 1);
2062   rb_define_method(klass, "add_enum", FileBuilderContext_add_enum, 1);
2063   rb_gc_register_address(&cFileBuilderContext);
2064   cFileBuilderContext = klass;
2065 }
2066 
2067 /*
2068  * call-seq:
2069  *     FileBuilderContext.new(descriptor_pool) => context
2070  *
2071  * Create a new file builder context for the given file descriptor and
2072  * builder context. This class is intended to serve as a DSL context to be used
2073  * with #instance_eval.
2074  */
FileBuilderContext_initialize(VALUE _self,VALUE descriptor_pool,VALUE name,VALUE options)2075 VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
2076                                     VALUE name, VALUE options) {
2077   DEFINE_SELF(FileBuilderContext, self, _self);
2078   self->descriptor_pool = descriptor_pool;
2079 
2080   google_protobuf_FileDescriptorProto_set_name(
2081       self->file_proto, FileBuilderContext_strdup(_self, name));
2082 
2083   // Default syntax for Ruby is proto3.
2084   google_protobuf_FileDescriptorProto_set_syntax(
2085       self->file_proto,
2086       FileBuilderContext_strdup(_self, rb_str_new2("proto3")));
2087 
2088   if (options != Qnil) {
2089     VALUE syntax;
2090 
2091     Check_Type(options, T_HASH);
2092     syntax = rb_hash_lookup2(options, ID2SYM(rb_intern("syntax")), Qnil);
2093 
2094     if (syntax != Qnil) {
2095       VALUE syntax_str;
2096 
2097       Check_Type(syntax, T_SYMBOL);
2098       syntax_str = rb_id2str(SYM2ID(syntax));
2099       google_protobuf_FileDescriptorProto_set_syntax(
2100           self->file_proto, FileBuilderContext_strdup(_self, syntax_str));
2101     }
2102   }
2103 
2104   return Qnil;
2105 }
2106 
2107 /*
2108  * call-seq:
2109  *     FileBuilderContext.add_message(name, &block)
2110  *
2111  * Creates a new, empty descriptor with the given name, and invokes the block in
2112  * the context of a MessageBuilderContext on that descriptor. The block can then
2113  * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
2114  * methods to define the message fields.
2115  *
2116  * This is the recommended, idiomatic way to build message definitions.
2117  */
FileBuilderContext_add_message(VALUE _self,VALUE name)2118 VALUE FileBuilderContext_add_message(VALUE _self, VALUE name) {
2119   VALUE args[2] = { _self, name };
2120   VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
2121   VALUE block = rb_block_proc();
2122   rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
2123   MessageBuilderContext_add_synthetic_oneofs(ctx);
2124   return Qnil;
2125 }
2126 
2127 /*
2128  * call-seq:
2129  *     FileBuilderContext.add_enum(name, &block)
2130  *
2131  * Creates a new, empty enum descriptor with the given name, and invokes the
2132  * block in the context of an EnumBuilderContext on that descriptor. The block
2133  * can then call EnumBuilderContext#add_value to define the enum values.
2134  *
2135  * This is the recommended, idiomatic way to build enum definitions.
2136  */
FileBuilderContext_add_enum(VALUE _self,VALUE name)2137 VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name) {
2138   VALUE args[2] = { _self, name };
2139   VALUE ctx = rb_class_new_instance(2, args, cEnumBuilderContext);
2140   VALUE block = rb_block_proc();
2141   rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
2142   return Qnil;
2143 }
2144 
FileBuilderContext_build(VALUE _self)2145 void FileBuilderContext_build(VALUE _self) {
2146   DEFINE_SELF(FileBuilderContext, self, _self);
2147   DescriptorPool* pool = ruby_to_DescriptorPool(self->descriptor_pool);
2148   upb_status status;
2149 
2150   rewrite_enum_defaults(pool->symtab, self->file_proto);
2151   rewrite_names(_self, self->file_proto);
2152 
2153   upb_status_clear(&status);
2154   if (!upb_symtab_addfile(pool->symtab, self->file_proto, &status)) {
2155     rb_raise(cTypeError, "Unable to add defs to DescriptorPool: %s",
2156              upb_status_errmsg(&status));
2157   }
2158 }
2159 
2160 // -----------------------------------------------------------------------------
2161 // Builder.
2162 // -----------------------------------------------------------------------------
2163 
2164 DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder");
2165 
Builder_mark(void * _self)2166 void Builder_mark(void* _self) {
2167   Builder* self = _self;
2168   rb_gc_mark(self->descriptor_pool);
2169   rb_gc_mark(self->default_file_builder);
2170 }
2171 
Builder_free(void * _self)2172 void Builder_free(void* _self) {
2173   xfree(_self);
2174 }
2175 
Builder_alloc(VALUE klass)2176 VALUE Builder_alloc(VALUE klass) {
2177   Builder* self = ALLOC(Builder);
2178   VALUE ret = TypedData_Wrap_Struct(
2179       klass, &_Builder_type, self);
2180   self->descriptor_pool = Qnil;
2181   self->default_file_builder = Qnil;
2182   return ret;
2183 }
2184 
Builder_register(VALUE module)2185 void Builder_register(VALUE module) {
2186   VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
2187   rb_define_alloc_func(klass, Builder_alloc);
2188   rb_define_method(klass, "initialize", Builder_initialize, 1);
2189   rb_define_method(klass, "add_file", Builder_add_file, -1);
2190   rb_define_method(klass, "add_message", Builder_add_message, 1);
2191   rb_define_method(klass, "add_enum", Builder_add_enum, 1);
2192   rb_gc_register_address(&cBuilder);
2193   cBuilder = klass;
2194 }
2195 
2196 /*
2197  * call-seq:
2198  *     Builder.new(descriptor_pool) => builder
2199  *
2200  * Creates a new Builder. A Builder can accumulate a set of new message and enum
2201  * descriptors and atomically register them into a pool in a way that allows for
2202  * (co)recursive type references.
2203  */
Builder_initialize(VALUE _self,VALUE pool)2204 VALUE Builder_initialize(VALUE _self, VALUE pool) {
2205   DEFINE_SELF(Builder, self, _self);
2206   self->descriptor_pool = pool;
2207   self->default_file_builder = Qnil;  // Created lazily if needed.
2208   return Qnil;
2209 }
2210 
2211 /*
2212  * call-seq:
2213  *     Builder.add_file(name, options = nil, &block)
2214  *
2215  * Creates a new, file descriptor with the given name and options and invokes
2216  * the block in the context of a FileBuilderContext on that descriptor. The
2217  * block can then call FileBuilderContext#add_message or
2218  * FileBuilderContext#add_enum to define new messages or enums, respectively.
2219  *
2220  * This is the recommended, idiomatic way to build file descriptors.
2221  */
Builder_add_file(int argc,VALUE * argv,VALUE _self)2222 VALUE Builder_add_file(int argc, VALUE* argv, VALUE _self) {
2223   DEFINE_SELF(Builder, self, _self);
2224   VALUE name, options;
2225   VALUE ctx;
2226   VALUE block;
2227 
2228   rb_scan_args(argc, argv, "11", &name, &options);
2229 
2230   {
2231     VALUE args[3] = { self->descriptor_pool, name, options };
2232     ctx = rb_class_new_instance(3, args, cFileBuilderContext);
2233   }
2234 
2235   block = rb_block_proc();
2236   rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
2237   FileBuilderContext_build(ctx);
2238 
2239   return Qnil;
2240 }
2241 
Builder_get_default_file(VALUE _self)2242 static VALUE Builder_get_default_file(VALUE _self) {
2243   DEFINE_SELF(Builder, self, _self);
2244 
2245   /* Lazily create only if legacy builder-level methods are called. */
2246   if (self->default_file_builder == Qnil) {
2247     VALUE name = rb_str_new2("ruby_default_file.proto");
2248     VALUE args [3] = { self->descriptor_pool, name, rb_hash_new() };
2249     self->default_file_builder =
2250         rb_class_new_instance(3, args, cFileBuilderContext);
2251   }
2252 
2253   return self->default_file_builder;
2254 }
2255 
2256 /*
2257  * call-seq:
2258  *     Builder.add_message(name, &block)
2259  *
2260  * Old and deprecated way to create a new descriptor.
2261  * See FileBuilderContext.add_message for the recommended way.
2262  *
2263  * Exists for backwards compatibility to allow building descriptor pool for
2264  * files generated by protoc which don't add messages within "add_file" block.
2265  * Descriptors created this way get assigned to a default empty FileDescriptor.
2266  */
Builder_add_message(VALUE _self,VALUE name)2267 VALUE Builder_add_message(VALUE _self, VALUE name) {
2268   VALUE file_builder = Builder_get_default_file(_self);
2269   rb_funcall_with_block(file_builder, rb_intern("add_message"), 1, &name,
2270                         rb_block_proc());
2271   return Qnil;
2272 }
2273 
2274 /*
2275  * call-seq:
2276  *     Builder.add_enum(name, &block)
2277  *
2278  * Old and deprecated way to create a new enum descriptor.
2279  * See FileBuilderContext.add_enum for the recommended way.
2280  *
2281  * Exists for backwards compatibility to allow building descriptor pool for
2282  * files generated by protoc which don't add enums within "add_file" block.
2283  * Enum descriptors created this way get assigned to a default empty
2284  * FileDescriptor.
2285  */
Builder_add_enum(VALUE _self,VALUE name)2286 VALUE Builder_add_enum(VALUE _self, VALUE name) {
2287   VALUE file_builder = Builder_get_default_file(_self);
2288   rb_funcall_with_block(file_builder, rb_intern("add_enum"), 1, &name,
2289                         rb_block_proc());
2290   return Qnil;
2291 }
2292 
2293 /* This method is hidden from Ruby, and only called directly from
2294  * DescriptorPool_build(). */
Builder_build(VALUE _self)2295 VALUE Builder_build(VALUE _self) {
2296   DEFINE_SELF(Builder, self, _self);
2297 
2298   if (self->default_file_builder != Qnil) {
2299     FileBuilderContext_build(self->default_file_builder);
2300     self->default_file_builder = Qnil;
2301   }
2302 
2303   return Qnil;
2304 }
2305 
get_def_obj(VALUE _descriptor_pool,const void * ptr,VALUE klass)2306 static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
2307   DEFINE_SELF(DescriptorPool, descriptor_pool, _descriptor_pool);
2308   VALUE key = ULL2NUM((intptr_t)ptr);
2309   VALUE def;
2310 
2311   def = rb_hash_aref(descriptor_pool->def_to_descriptor, key);
2312 
2313   if (ptr == NULL) {
2314     return Qnil;
2315   }
2316 
2317   if (def == Qnil) {
2318     // Lazily create wrapper object.
2319     VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
2320     def = rb_class_new_instance(3, args, klass);
2321     rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
2322 
2323     // For message defs, we now eagerly get/create descriptors for all
2324     // submessages.  We will need these anyway to parse or serialize this
2325     // message type.  But more importantly, we must do this now so that
2326     // add_handlers_for_message() (which calls get_msgdef_obj()) does *not*
2327     // need to create a Ruby object or insert into a Ruby Hash.  We need to
2328     // avoid triggering GC, which can switch Ruby threads and re-enter our
2329     // C extension from a different thread.  This wreaks havoc on our state
2330     // if we were in the middle of building handlers.
2331     if (klass == cDescriptor) {
2332       const upb_msgdef *m = ptr;
2333       upb_msg_field_iter it;
2334       for (upb_msg_field_begin(&it, m);
2335            !upb_msg_field_done(&it);
2336            upb_msg_field_next(&it)) {
2337         const upb_fielddef* f = upb_msg_iter_field(&it);
2338         if (upb_fielddef_issubmsg(f)) {
2339           get_msgdef_obj(_descriptor_pool, upb_fielddef_msgsubdef(f));
2340         }
2341       }
2342     }
2343   }
2344 
2345   return def;
2346 }
2347 
get_msgdef_obj(VALUE descriptor_pool,const upb_msgdef * def)2348 VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def) {
2349   return get_def_obj(descriptor_pool, def, cDescriptor);
2350 }
2351 
get_enumdef_obj(VALUE descriptor_pool,const upb_enumdef * def)2352 VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def) {
2353   return get_def_obj(descriptor_pool, def, cEnumDescriptor);
2354 }
2355 
get_fielddef_obj(VALUE descriptor_pool,const upb_fielddef * def)2356 VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def) {
2357   return get_def_obj(descriptor_pool, def, cFieldDescriptor);
2358 }
2359 
get_filedef_obj(VALUE descriptor_pool,const upb_filedef * def)2360 VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def) {
2361   return get_def_obj(descriptor_pool, def, cFileDescriptor);
2362 }
2363 
get_oneofdef_obj(VALUE descriptor_pool,const upb_oneofdef * def)2364 VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def) {
2365   return get_def_obj(descriptor_pool, def, cOneofDescriptor);
2366 }
2367