• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include <ctype.h>
9 #include <errno.h>
10 
11 #include "convert.h"
12 #include "message.h"
13 #include "protobuf.h"
14 
15 // -----------------------------------------------------------------------------
16 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
17 // instances.
18 // -----------------------------------------------------------------------------
19 
20 static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def);
21 static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def);
22 static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def);
23 static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def);
24 static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def);
25 static VALUE get_servicedef_obj(VALUE descriptor_pool,
26                                 const upb_ServiceDef* def);
27 static VALUE get_methoddef_obj(VALUE descriptor_pool, const upb_MethodDef* def);
28 
29 // A distinct object that is not accessible from Ruby.  We use this as a
30 // constructor argument to enforce that certain objects cannot be created from
31 // Ruby.
32 VALUE c_only_cookie = Qnil;
33 
34 // -----------------------------------------------------------------------------
35 // Common utilities.
36 // -----------------------------------------------------------------------------
37 
get_str(VALUE str)38 static const char* get_str(VALUE str) {
39   Check_Type(str, T_STRING);
40   return RSTRING_PTR(str);
41 }
42 
rb_str_maybe_null(const char * s)43 static VALUE rb_str_maybe_null(const char* s) {
44   if (s == NULL) {
45     s = "";
46   }
47   return rb_str_new2(s);
48 }
49 static ID options_instancevar_interned;
50 // -----------------------------------------------------------------------------
51 // DescriptorPool.
52 // -----------------------------------------------------------------------------
53 
54 typedef struct {
55   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
56   // macro to update VALUE references, as to trigger write barriers.
57   VALUE def_to_descriptor;  // Hash table of def* -> Ruby descriptor.
58   upb_DefPool* symtab;
59 } DescriptorPool;
60 
61 VALUE cDescriptorPool = Qnil;
62 
63 // Global singleton DescriptorPool. The user is free to create others, but this
64 // is used by generated code.
65 VALUE generated_pool = Qnil;
66 
DescriptorPool_mark(void * _self)67 static void DescriptorPool_mark(void* _self) {
68   DescriptorPool* self = _self;
69   rb_gc_mark(self->def_to_descriptor);
70 }
71 
DescriptorPool_free(void * _self)72 static void DescriptorPool_free(void* _self) {
73   DescriptorPool* self = _self;
74   upb_DefPool_Free(self->symtab);
75   xfree(self);
76 }
77 
78 static const rb_data_type_t DescriptorPool_type = {
79     "Google::Protobuf::DescriptorPool",
80     {DescriptorPool_mark, DescriptorPool_free, NULL},
81     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
82 };
83 
ruby_to_DescriptorPool(VALUE val)84 static DescriptorPool* ruby_to_DescriptorPool(VALUE val) {
85   DescriptorPool* ret;
86   TypedData_Get_Struct(val, DescriptorPool, &DescriptorPool_type, ret);
87   return ret;
88 }
89 
90 // Exposed to other modules in defs.h.
DescriptorPool_GetSymtab(VALUE desc_pool_rb)91 const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb) {
92   DescriptorPool* pool = ruby_to_DescriptorPool(desc_pool_rb);
93   return pool->symtab;
94 }
95 
96 /*
97  * call-seq:
98  *     DescriptorPool.new => pool
99  *
100  * Creates a new, empty, descriptor pool.
101  */
DescriptorPool_alloc(VALUE klass)102 static VALUE DescriptorPool_alloc(VALUE klass) {
103   DescriptorPool* self = ALLOC(DescriptorPool);
104   VALUE ret;
105 
106   self->def_to_descriptor = Qnil;
107   ret = TypedData_Wrap_Struct(klass, &DescriptorPool_type, self);
108 
109   RB_OBJ_WRITE(ret, &self->def_to_descriptor, rb_hash_new());
110   self->symtab = upb_DefPool_New();
111   return ObjectCache_TryAdd(self->symtab, ret);
112 }
113 
114 /*
115  * call-seq:
116  *     DescriptorPool.add_serialized_file(serialized_file_proto)
117  *
118  * Adds the given serialized FileDescriptorProto to the pool.
119  */
DescriptorPool_add_serialized_file(VALUE _self,VALUE serialized_file_proto)120 VALUE DescriptorPool_add_serialized_file(VALUE _self,
121                                          VALUE serialized_file_proto) {
122   DescriptorPool* self = ruby_to_DescriptorPool(_self);
123   Check_Type(serialized_file_proto, T_STRING);
124   VALUE arena_rb = Arena_new();
125   upb_Arena* arena = Arena_get(arena_rb);
126   google_protobuf_FileDescriptorProto* file_proto =
127       google_protobuf_FileDescriptorProto_parse(
128           RSTRING_PTR(serialized_file_proto),
129           RSTRING_LEN(serialized_file_proto), arena);
130   if (!file_proto) {
131     rb_raise(rb_eArgError, "Unable to parse FileDescriptorProto");
132   }
133   upb_Status status;
134   upb_Status_Clear(&status);
135   const upb_FileDef* filedef =
136       upb_DefPool_AddFile(self->symtab, file_proto, &status);
137   if (!filedef) {
138     rb_raise(cTypeError, "Unable to build file to DescriptorPool: %s",
139              upb_Status_ErrorMessage(&status));
140   }
141   RB_GC_GUARD(arena_rb);
142   return get_filedef_obj(_self, filedef);
143 }
144 
145 /*
146  * call-seq:
147  *     DescriptorPool.lookup(name) => descriptor
148  *
149  * Finds a Descriptor, EnumDescriptor or FieldDescriptor by name and returns it,
150  * or nil if none exists with the given name.
151  */
DescriptorPool_lookup(VALUE _self,VALUE name)152 static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
153   DescriptorPool* self = ruby_to_DescriptorPool(_self);
154   const char* name_str = get_str(name);
155   const upb_MessageDef* msgdef;
156   const upb_EnumDef* enumdef;
157   const upb_FieldDef* fielddef;
158   const upb_ServiceDef* servicedef;
159 
160   msgdef = upb_DefPool_FindMessageByName(self->symtab, name_str);
161   if (msgdef) {
162     return get_msgdef_obj(_self, msgdef);
163   }
164 
165   fielddef = upb_DefPool_FindExtensionByName(self->symtab, name_str);
166   if (fielddef) {
167     return get_fielddef_obj(_self, fielddef);
168   }
169 
170   enumdef = upb_DefPool_FindEnumByName(self->symtab, name_str);
171   if (enumdef) {
172     return get_enumdef_obj(_self, enumdef);
173   }
174 
175   servicedef = upb_DefPool_FindServiceByName(self->symtab, name_str);
176   if (servicedef) {
177     return get_servicedef_obj(_self, servicedef);
178   }
179 
180   return Qnil;
181 }
182 
183 /*
184  * call-seq:
185  *     DescriptorPool.generated_pool => descriptor_pool
186  *
187  * Class method that returns the global DescriptorPool. This is a singleton into
188  * which generated-code message and enum types are registered. The user may also
189  * register types in this pool for convenience so that they do not have to hold
190  * a reference to a private pool instance.
191  */
DescriptorPool_generated_pool(VALUE _self)192 static VALUE DescriptorPool_generated_pool(VALUE _self) {
193   return generated_pool;
194 }
195 
DescriptorPool_register(VALUE module)196 static void DescriptorPool_register(VALUE module) {
197   VALUE klass = rb_define_class_under(module, "DescriptorPool", rb_cObject);
198   rb_define_alloc_func(klass, DescriptorPool_alloc);
199   rb_define_method(klass, "add_serialized_file",
200                    DescriptorPool_add_serialized_file, 1);
201   rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
202   rb_define_singleton_method(klass, "generated_pool",
203                              DescriptorPool_generated_pool, 0);
204   rb_gc_register_address(&cDescriptorPool);
205   cDescriptorPool = klass;
206 
207   rb_gc_register_address(&generated_pool);
208   generated_pool = rb_class_new_instance(0, NULL, klass);
209   options_instancevar_interned = rb_intern("options");
210 }
211 
212 // -----------------------------------------------------------------------------
213 // Descriptor.
214 // -----------------------------------------------------------------------------
215 
216 typedef struct {
217   const upb_MessageDef* msgdef;
218   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
219   // macro to update VALUE references, as to trigger write barriers.
220   VALUE klass;
221   VALUE descriptor_pool;
222 } Descriptor;
223 
224 VALUE cDescriptor = Qnil;
225 
Descriptor_mark(void * _self)226 static void Descriptor_mark(void* _self) {
227   Descriptor* self = _self;
228   rb_gc_mark(self->klass);
229   rb_gc_mark(self->descriptor_pool);
230 }
231 
232 static const rb_data_type_t Descriptor_type = {
233     "Google::Protobuf::Descriptor",
234     {Descriptor_mark, RUBY_DEFAULT_FREE, NULL},
235     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
236 };
237 
ruby_to_Descriptor(VALUE val)238 static Descriptor* ruby_to_Descriptor(VALUE val) {
239   Descriptor* ret;
240   TypedData_Get_Struct(val, Descriptor, &Descriptor_type, ret);
241   return ret;
242 }
243 
244 // Decode and return a frozen instance of a Descriptor Option for the given pool
decode_options(VALUE self,const char * option_type,int size,const char * bytes,VALUE descriptor_pool)245 static VALUE decode_options(VALUE self, const char* option_type, int size,
246                             const char* bytes, VALUE descriptor_pool) {
247   VALUE options_rb = rb_ivar_get(self, options_instancevar_interned);
248   if (options_rb != Qnil) {
249     return options_rb;
250   }
251 
252   static const char* prefix = "google.protobuf.";
253   char fullname
254       [/*strlen(prefix)*/ 16 +
255        /*strln(longest option type supported e.g. "MessageOptions")*/ 14 +
256        /*null terminator*/ 1];
257 
258   snprintf(fullname, sizeof(fullname), "%s%s", prefix, option_type);
259   const upb_MessageDef* msgdef = upb_DefPool_FindMessageByName(
260       ruby_to_DescriptorPool(descriptor_pool)->symtab, fullname);
261   if (!msgdef) {
262     rb_raise(rb_eRuntimeError, "Cannot find %s in DescriptorPool", option_type);
263   }
264 
265   VALUE desc_rb = get_msgdef_obj(descriptor_pool, msgdef);
266   const Descriptor* desc = ruby_to_Descriptor(desc_rb);
267 
268   options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, false);
269 
270   // Strip features from the options proto to keep it internal.
271   const upb_MessageDef* decoded_desc = NULL;
272   upb_Message* options = Message_GetMutable(options_rb, &decoded_desc);
273   PBRUBY_ASSERT(options != NULL);
274   PBRUBY_ASSERT(decoded_desc == msgdef);
275   const upb_FieldDef* field =
276       upb_MessageDef_FindFieldByName(decoded_desc, "features");
277   PBRUBY_ASSERT(field != NULL);
278   upb_Message_ClearFieldByDef(options, field);
279 
280   Message_freeze(options_rb);
281 
282   rb_ivar_set(self, options_instancevar_interned, options_rb);
283   return options_rb;
284 }
285 
286 /*
287  * call-seq:
288  *     Descriptor.new => descriptor
289  *
290  * Creates a new, empty, message type descriptor. At a minimum, its name must be
291  * set before it is added to a pool. It cannot be used to create messages until
292  * it is added to a pool, after which it becomes immutable (as part of a
293  * finalization process).
294  */
Descriptor_alloc(VALUE klass)295 static VALUE Descriptor_alloc(VALUE klass) {
296   Descriptor* self = ALLOC(Descriptor);
297   VALUE ret = TypedData_Wrap_Struct(klass, &Descriptor_type, self);
298   self->msgdef = NULL;
299   self->klass = Qnil;
300   self->descriptor_pool = Qnil;
301   return ret;
302 }
303 
304 /*
305  * call-seq:
306  *    Descriptor.new(c_only_cookie, ptr) => Descriptor
307  *
308  * Creates a descriptor wrapper object.  May only be called from C.
309  */
Descriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)310 static VALUE Descriptor_initialize(VALUE _self, VALUE cookie,
311                                    VALUE descriptor_pool, VALUE ptr) {
312   Descriptor* self = ruby_to_Descriptor(_self);
313 
314   if (cookie != c_only_cookie) {
315     rb_raise(rb_eRuntimeError,
316              "Descriptor objects may not be created from Ruby.");
317   }
318 
319   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
320   self->msgdef = (const upb_MessageDef*)NUM2ULL(ptr);
321 
322   return Qnil;
323 }
324 
325 /*
326  * call-seq:
327  *    Descriptor.file_descriptor
328  *
329  * Returns the FileDescriptor object this message belongs to.
330  */
Descriptor_file_descriptor(VALUE _self)331 static VALUE Descriptor_file_descriptor(VALUE _self) {
332   Descriptor* self = ruby_to_Descriptor(_self);
333   return get_filedef_obj(self->descriptor_pool,
334                          upb_MessageDef_File(self->msgdef));
335 }
336 
337 /*
338  * call-seq:
339  *     Descriptor.name => name
340  *
341  * Returns the name of this message type as a fully-qualified string (e.g.,
342  * My.Package.MessageType).
343  */
Descriptor_name(VALUE _self)344 static VALUE Descriptor_name(VALUE _self) {
345   Descriptor* self = ruby_to_Descriptor(_self);
346   return rb_str_maybe_null(upb_MessageDef_FullName(self->msgdef));
347 }
348 
349 /*
350  * call-seq:
351  *     Descriptor.each(&block)
352  *
353  * Iterates over fields in this message type, yielding to the block on each one.
354  */
Descriptor_each(VALUE _self)355 static VALUE Descriptor_each(VALUE _self) {
356   Descriptor* self = ruby_to_Descriptor(_self);
357 
358   int n = upb_MessageDef_FieldCount(self->msgdef);
359   for (int i = 0; i < n; i++) {
360     const upb_FieldDef* field = upb_MessageDef_Field(self->msgdef, i);
361     VALUE obj = get_fielddef_obj(self->descriptor_pool, field);
362     rb_yield(obj);
363   }
364   return Qnil;
365 }
366 
367 /*
368  * call-seq:
369  *     Descriptor.lookup(name) => FieldDescriptor
370  *
371  * Returns the field descriptor for the field with the given name, if present,
372  * or nil if none.
373  */
Descriptor_lookup(VALUE _self,VALUE name)374 static VALUE Descriptor_lookup(VALUE _self, VALUE name) {
375   Descriptor* self = ruby_to_Descriptor(_self);
376   const char* s = get_str(name);
377   const upb_FieldDef* field = upb_MessageDef_FindFieldByName(self->msgdef, s);
378   if (field == NULL) {
379     return Qnil;
380   }
381   return get_fielddef_obj(self->descriptor_pool, field);
382 }
383 
384 /*
385  * call-seq:
386  *     Descriptor.each_oneof(&block) => nil
387  *
388  * Invokes the given block for each oneof in this message type, passing the
389  * corresponding OneofDescriptor.
390  */
Descriptor_each_oneof(VALUE _self)391 static VALUE Descriptor_each_oneof(VALUE _self) {
392   Descriptor* self = ruby_to_Descriptor(_self);
393 
394   int n = upb_MessageDef_OneofCount(self->msgdef);
395   for (int i = 0; i < n; i++) {
396     const upb_OneofDef* oneof = upb_MessageDef_Oneof(self->msgdef, i);
397     VALUE obj = get_oneofdef_obj(self->descriptor_pool, oneof);
398     rb_yield(obj);
399   }
400   return Qnil;
401 }
402 
403 /*
404  * call-seq:
405  *     Descriptor.lookup_oneof(name) => OneofDescriptor
406  *
407  * Returns the oneof descriptor for the oneof with the given name, if present,
408  * or nil if none.
409  */
Descriptor_lookup_oneof(VALUE _self,VALUE name)410 static VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
411   Descriptor* self = ruby_to_Descriptor(_self);
412   const char* s = get_str(name);
413   const upb_OneofDef* oneof = upb_MessageDef_FindOneofByName(self->msgdef, s);
414   if (oneof == NULL) {
415     return Qnil;
416   }
417   return get_oneofdef_obj(self->descriptor_pool, oneof);
418 }
419 
420 /*
421  * call-seq:
422  *     Descriptor.msgclass => message_klass
423  *
424  * Returns the Ruby class created for this message type.
425  */
Descriptor_msgclass(VALUE _self)426 static VALUE Descriptor_msgclass(VALUE _self) {
427   Descriptor* self = ruby_to_Descriptor(_self);
428   if (self->klass == Qnil) {
429     RB_OBJ_WRITE(_self, &self->klass, build_class_from_descriptor(_self));
430   }
431   return self->klass;
432 }
433 
434 /*
435  * call-seq:
436  *     Descriptor.options => options
437  *
438  * Returns the `MessageOptions` for this `Descriptor`.
439  */
Descriptor_options(VALUE _self)440 static VALUE Descriptor_options(VALUE _self) {
441   Descriptor* self = ruby_to_Descriptor(_self);
442   const google_protobuf_MessageOptions* opts =
443       upb_MessageDef_Options(self->msgdef);
444   upb_Arena* arena = upb_Arena_New();
445   size_t size;
446   char* serialized =
447       google_protobuf_MessageOptions_serialize(opts, arena, &size);
448   VALUE message_options = decode_options(_self, "MessageOptions", size,
449                                          serialized, self->descriptor_pool);
450   upb_Arena_Free(arena);
451   return message_options;
452 }
453 
Descriptor_register(VALUE module)454 static void Descriptor_register(VALUE module) {
455   VALUE klass = rb_define_class_under(module, "Descriptor", rb_cObject);
456   rb_define_alloc_func(klass, Descriptor_alloc);
457   rb_define_method(klass, "initialize", Descriptor_initialize, 3);
458   rb_define_method(klass, "each", Descriptor_each, 0);
459   rb_define_method(klass, "lookup", Descriptor_lookup, 1);
460   rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
461   rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
462   rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
463   rb_define_method(klass, "name", Descriptor_name, 0);
464   rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0);
465   rb_define_method(klass, "options", Descriptor_options, 0);
466   rb_include_module(klass, rb_mEnumerable);
467   rb_gc_register_address(&cDescriptor);
468   cDescriptor = klass;
469 }
470 
471 // -----------------------------------------------------------------------------
472 // FileDescriptor.
473 // -----------------------------------------------------------------------------
474 
475 typedef struct {
476   const upb_FileDef* filedef;
477   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
478   // macro to update VALUE references, as to trigger write barriers.
479   VALUE descriptor_pool;  // Owns the upb_FileDef.
480 } FileDescriptor;
481 
482 static VALUE cFileDescriptor = Qnil;
483 
FileDescriptor_mark(void * _self)484 static void FileDescriptor_mark(void* _self) {
485   FileDescriptor* self = _self;
486   rb_gc_mark(self->descriptor_pool);
487 }
488 
489 static const rb_data_type_t FileDescriptor_type = {
490     "Google::Protobuf::FileDescriptor",
491     {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
492     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
493 };
494 
ruby_to_FileDescriptor(VALUE val)495 static FileDescriptor* ruby_to_FileDescriptor(VALUE val) {
496   FileDescriptor* ret;
497   TypedData_Get_Struct(val, FileDescriptor, &FileDescriptor_type, ret);
498   return ret;
499 }
500 
FileDescriptor_alloc(VALUE klass)501 static VALUE FileDescriptor_alloc(VALUE klass) {
502   FileDescriptor* self = ALLOC(FileDescriptor);
503   VALUE ret = TypedData_Wrap_Struct(klass, &FileDescriptor_type, self);
504   self->descriptor_pool = Qnil;
505   self->filedef = NULL;
506   return ret;
507 }
508 
509 /*
510  * call-seq:
511  *     FileDescriptor.new => file
512  *
513  * Returns a new file descriptor. May
514  * to a builder.
515  */
FileDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)516 static VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
517                                        VALUE descriptor_pool, VALUE ptr) {
518   FileDescriptor* self = ruby_to_FileDescriptor(_self);
519 
520   if (cookie != c_only_cookie) {
521     rb_raise(rb_eRuntimeError,
522              "Descriptor objects may not be created from Ruby.");
523   }
524 
525   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
526   self->filedef = (const upb_FileDef*)NUM2ULL(ptr);
527 
528   return Qnil;
529 }
530 
531 /*
532  * call-seq:
533  *     FileDescriptor.name => name
534  *
535  * Returns the name of the file.
536  */
FileDescriptor_name(VALUE _self)537 static VALUE FileDescriptor_name(VALUE _self) {
538   FileDescriptor* self = ruby_to_FileDescriptor(_self);
539   const char* name = upb_FileDef_Name(self->filedef);
540   return name == NULL ? Qnil : rb_str_new2(name);
541 }
542 
543 /*
544  * call-seq:
545  *     FileDescriptor.options => options
546  *
547  * Returns the `FileOptions` for this `FileDescriptor`.
548  */
FileDescriptor_options(VALUE _self)549 static VALUE FileDescriptor_options(VALUE _self) {
550   FileDescriptor* self = ruby_to_FileDescriptor(_self);
551   const google_protobuf_FileOptions* opts = upb_FileDef_Options(self->filedef);
552   upb_Arena* arena = upb_Arena_New();
553   size_t size;
554   char* serialized = google_protobuf_FileOptions_serialize(opts, arena, &size);
555   VALUE file_options = decode_options(_self, "FileOptions", size, serialized,
556                                       self->descriptor_pool);
557   upb_Arena_Free(arena);
558   return file_options;
559 }
560 
FileDescriptor_register(VALUE module)561 static void FileDescriptor_register(VALUE module) {
562   VALUE klass = rb_define_class_under(module, "FileDescriptor", rb_cObject);
563   rb_define_alloc_func(klass, FileDescriptor_alloc);
564   rb_define_method(klass, "initialize", FileDescriptor_initialize, 3);
565   rb_define_method(klass, "name", FileDescriptor_name, 0);
566   rb_define_method(klass, "options", FileDescriptor_options, 0);
567   rb_gc_register_address(&cFileDescriptor);
568   cFileDescriptor = klass;
569 }
570 
571 // -----------------------------------------------------------------------------
572 // FieldDescriptor.
573 // -----------------------------------------------------------------------------
574 
575 typedef struct {
576   const upb_FieldDef* fielddef;
577   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
578   // macro to update VALUE references, as to trigger write barriers.
579   VALUE descriptor_pool;  // Owns the upb_FieldDef.
580 } FieldDescriptor;
581 
582 static VALUE cFieldDescriptor = Qnil;
583 
FieldDescriptor_mark(void * _self)584 static void FieldDescriptor_mark(void* _self) {
585   FieldDescriptor* self = _self;
586   rb_gc_mark(self->descriptor_pool);
587 }
588 
589 static const rb_data_type_t FieldDescriptor_type = {
590     "Google::Protobuf::FieldDescriptor",
591     {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
592     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
593 };
594 
ruby_to_FieldDescriptor(VALUE val)595 static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) {
596   FieldDescriptor* ret;
597   TypedData_Get_Struct(val, FieldDescriptor, &FieldDescriptor_type, ret);
598   return ret;
599 }
600 
601 /*
602  * call-seq:
603  *     FieldDescriptor.new => field
604  *
605  * Returns a new field descriptor. Its name, type, etc. must be set before it is
606  * added to a message type.
607  */
FieldDescriptor_alloc(VALUE klass)608 static VALUE FieldDescriptor_alloc(VALUE klass) {
609   FieldDescriptor* self = ALLOC(FieldDescriptor);
610   VALUE ret = TypedData_Wrap_Struct(klass, &FieldDescriptor_type, self);
611   self->fielddef = NULL;
612   return ret;
613 }
614 
615 /*
616  * call-seq:
617  *    FieldDescriptor.new(c_only_cookie, pool, ptr) => FieldDescriptor
618  *
619  * Creates a descriptor wrapper object.  May only be called from C.
620  */
FieldDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)621 static VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
622                                         VALUE descriptor_pool, VALUE ptr) {
623   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
624 
625   if (cookie != c_only_cookie) {
626     rb_raise(rb_eRuntimeError,
627              "Descriptor objects may not be created from Ruby.");
628   }
629 
630   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
631   self->fielddef = (const upb_FieldDef*)NUM2ULL(ptr);
632 
633   return Qnil;
634 }
635 
636 /*
637  * call-seq:
638  *     FieldDescriptor.name => name
639  *
640  * Returns the name of this field.
641  */
FieldDescriptor_name(VALUE _self)642 static VALUE FieldDescriptor_name(VALUE _self) {
643   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
644   return rb_str_maybe_null(upb_FieldDef_Name(self->fielddef));
645 }
646 
647 // Non-static, exposed to other .c files.
ruby_to_fieldtype(VALUE type)648 upb_CType ruby_to_fieldtype(VALUE type) {
649   if (TYPE(type) != T_SYMBOL) {
650     rb_raise(rb_eArgError, "Expected symbol for field type.");
651   }
652 
653 #define CONVERT(upb, ruby)                \
654   if (SYM2ID(type) == rb_intern(#ruby)) { \
655     return kUpb_CType_##upb;              \
656   }
657 
658   CONVERT(Float, float);
659   CONVERT(Double, double);
660   CONVERT(Bool, bool);
661   CONVERT(String, string);
662   CONVERT(Bytes, bytes);
663   CONVERT(Message, message);
664   CONVERT(Enum, enum);
665   CONVERT(Int32, int32);
666   CONVERT(Int64, int64);
667   CONVERT(UInt32, uint32);
668   CONVERT(UInt64, uint64);
669 
670 #undef CONVERT
671 
672   rb_raise(rb_eArgError, "Unknown field type.");
673   return 0;
674 }
675 
descriptortype_to_ruby(upb_FieldType type)676 static VALUE descriptortype_to_ruby(upb_FieldType type) {
677   switch (type) {
678 #define CONVERT(upb, ruby)   \
679   case kUpb_FieldType_##upb: \
680     return ID2SYM(rb_intern(#ruby));
681     CONVERT(Float, float);
682     CONVERT(Double, double);
683     CONVERT(Bool, bool);
684     CONVERT(String, string);
685     CONVERT(Bytes, bytes);
686     CONVERT(Message, message);
687     CONVERT(Group, group);
688     CONVERT(Enum, enum);
689     CONVERT(Int32, int32);
690     CONVERT(Int64, int64);
691     CONVERT(UInt32, uint32);
692     CONVERT(UInt64, uint64);
693     CONVERT(SInt32, sint32);
694     CONVERT(SInt64, sint64);
695     CONVERT(Fixed32, fixed32);
696     CONVERT(Fixed64, fixed64);
697     CONVERT(SFixed32, sfixed32);
698     CONVERT(SFixed64, sfixed64);
699 #undef CONVERT
700   }
701   return Qnil;
702 }
703 
704 /*
705  * call-seq:
706  *     FieldDescriptor.type => type
707  *
708  * Returns this field's type, as a Ruby symbol, or nil if not yet set.
709  *
710  * Valid field types are:
711  *     :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
712  *     :bytes, :message.
713  */
FieldDescriptor__type(VALUE _self)714 static VALUE FieldDescriptor__type(VALUE _self) {
715   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
716   return descriptortype_to_ruby(upb_FieldDef_Type(self->fielddef));
717 }
718 
719 /*
720  * call-seq:
721  *     FieldDescriptor.default => default
722  *
723  * Returns this field's default, as a Ruby object, or nil if not yet set.
724  */
FieldDescriptor_default(VALUE _self)725 static VALUE FieldDescriptor_default(VALUE _self) {
726   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
727   const upb_FieldDef* f = self->fielddef;
728   upb_MessageValue default_val = upb_MessageValue_Zero();
729   if (upb_FieldDef_IsSubMessage(f)) {
730     return Qnil;
731   } else if (!upb_FieldDef_IsRepeated(f)) {
732     default_val = upb_FieldDef_Default(f);
733   }
734   return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
735 }
736 
737 /*
738  * call-seq:
739  *     FieldDescriptor.has_presence? => bool
740  *
741  * Returns whether this field tracks presence.
742  */
FieldDescriptor_has_presence(VALUE _self)743 static VALUE FieldDescriptor_has_presence(VALUE _self) {
744   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
745   return upb_FieldDef_HasPresence(self->fielddef) ? Qtrue : Qfalse;
746 }
747 
748 /*
749  * call-seq:
750  *     FieldDescriptor.is_packed? => bool
751  *
752  * Returns whether this is a repeated field that uses packed encoding.
753  */
FieldDescriptor_is_packed(VALUE _self)754 static VALUE FieldDescriptor_is_packed(VALUE _self) {
755   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
756   return upb_FieldDef_IsPacked(self->fielddef) ? Qtrue : Qfalse;
757 }
758 
759 /*
760  * call-seq:
761  *     FieldDescriptor.json_name => json_name
762  *
763  * Returns this field's json_name, as a Ruby string, or nil if not yet set.
764  */
FieldDescriptor_json_name(VALUE _self)765 static VALUE FieldDescriptor_json_name(VALUE _self) {
766   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
767   const upb_FieldDef* f = self->fielddef;
768   const char* json_name = upb_FieldDef_JsonName(f);
769   return rb_str_new2(json_name);
770 }
771 
772 /*
773  * call-seq:
774  *     FieldDescriptor.label => label
775  *
776  * Returns this field's label (i.e., plurality), as a Ruby symbol.
777  *
778  * Valid field labels are:
779  *     :optional, :repeated
780  */
FieldDescriptor_label(VALUE _self)781 static VALUE FieldDescriptor_label(VALUE _self) {
782   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
783   switch (upb_FieldDef_Label(self->fielddef)) {
784 #define CONVERT(upb, ruby) \
785   case kUpb_Label_##upb:   \
786     return ID2SYM(rb_intern(#ruby));
787 
788     CONVERT(Optional, optional);
789     CONVERT(Required, required);
790     CONVERT(Repeated, repeated);
791 
792 #undef CONVERT
793   }
794 
795   return Qnil;
796 }
797 
798 /*
799  * call-seq:
800  *     FieldDescriptor.number => number
801  *
802  * Returns the tag number for this field.
803  */
FieldDescriptor_number(VALUE _self)804 static VALUE FieldDescriptor_number(VALUE _self) {
805   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
806   return INT2NUM(upb_FieldDef_Number(self->fielddef));
807 }
808 
809 /*
810  * call-seq:
811  *     FieldDescriptor.submsg_name => submsg_name
812  *
813  * Returns the name of the message or enum type corresponding to this field, if
814  * it is a message or enum field (respectively), or nil otherwise. This type
815  * name will be resolved within the context of the pool to which the containing
816  * message type is added.
817  */
FieldDescriptor_submsg_name(VALUE _self)818 static VALUE FieldDescriptor_submsg_name(VALUE _self) {
819   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
820   switch (upb_FieldDef_CType(self->fielddef)) {
821     case kUpb_CType_Enum:
822       return rb_str_new2(
823           upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(self->fielddef)));
824     case kUpb_CType_Message:
825       return rb_str_new2(
826           upb_MessageDef_FullName(upb_FieldDef_MessageSubDef(self->fielddef)));
827     default:
828       return Qnil;
829   }
830 }
831 
832 /*
833  * call-seq:
834  *     FieldDescriptor.subtype => message_or_enum_descriptor
835  *
836  * Returns the message or enum descriptor corresponding to this field's type if
837  * it is a message or enum field, respectively, or nil otherwise. Cannot be
838  * called *until* the containing message type is added to a pool (and thus
839  * resolved).
840  */
FieldDescriptor_subtype(VALUE _self)841 static VALUE FieldDescriptor_subtype(VALUE _self) {
842   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
843   switch (upb_FieldDef_CType(self->fielddef)) {
844     case kUpb_CType_Enum:
845       return get_enumdef_obj(self->descriptor_pool,
846                              upb_FieldDef_EnumSubDef(self->fielddef));
847     case kUpb_CType_Message:
848       return get_msgdef_obj(self->descriptor_pool,
849                             upb_FieldDef_MessageSubDef(self->fielddef));
850     default:
851       return Qnil;
852   }
853 }
854 
855 /*
856  * call-seq:
857  *     FieldDescriptor.get(message) => value
858  *
859  * Returns the value set for this field on the given message. Raises an
860  * exception if message is of the wrong type.
861  */
FieldDescriptor_get(VALUE _self,VALUE msg_rb)862 static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
863   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
864   const upb_MessageDef* m;
865 
866   Message_Get(msg_rb, &m);
867 
868   if (m != upb_FieldDef_ContainingType(self->fielddef)) {
869     rb_raise(cTypeError, "get method called on wrong message type");
870   }
871 
872   return Message_getfield(msg_rb, self->fielddef);
873 }
874 
875 /*
876  * call-seq:
877  *     FieldDescriptor.has?(message) => boolean
878  *
879  * Returns whether the value is set on the given message. Raises an
880  * exception when calling for fields that do not have presence.
881  */
FieldDescriptor_has(VALUE _self,VALUE msg_rb)882 static VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
883   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
884   const upb_MessageDef* m;
885   const upb_Message* msg = Message_Get(msg_rb, &m);
886 
887   if (m != upb_FieldDef_ContainingType(self->fielddef)) {
888     rb_raise(cTypeError, "has method called on wrong message type");
889   } else if (!upb_FieldDef_HasPresence(self->fielddef)) {
890     rb_raise(rb_eArgError, "does not track presence");
891   }
892 
893   return upb_Message_HasFieldByDef(msg, self->fielddef) ? Qtrue : Qfalse;
894 }
895 
896 /*
897  * call-seq:
898  *     FieldDescriptor.clear(message)
899  *
900  * Clears the field from the message if it's set.
901  */
FieldDescriptor_clear(VALUE _self,VALUE msg_rb)902 static VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
903   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
904   const upb_MessageDef* m;
905   upb_Message* msg = Message_GetMutable(msg_rb, &m);
906 
907   if (m != upb_FieldDef_ContainingType(self->fielddef)) {
908     rb_raise(cTypeError, "has method called on wrong message type");
909   }
910 
911   upb_Message_ClearFieldByDef(msg, self->fielddef);
912   return Qnil;
913 }
914 
915 /*
916  * call-seq:
917  *     FieldDescriptor.set(message, value)
918  *
919  * Sets the value corresponding to this field to the given value on the given
920  * message. Raises an exception if message is of the wrong type. Performs the
921  * ordinary type-checks for field setting.
922  */
FieldDescriptor_set(VALUE _self,VALUE msg_rb,VALUE value)923 static VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
924   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
925   const upb_MessageDef* m;
926   upb_Message* msg = Message_GetMutable(msg_rb, &m);
927   upb_Arena* arena = Arena_get(Message_GetArena(msg_rb));
928   upb_MessageValue msgval;
929 
930   if (m != upb_FieldDef_ContainingType(self->fielddef)) {
931     rb_raise(cTypeError, "set method called on wrong message type");
932   }
933 
934   msgval = Convert_RubyToUpb(value, upb_FieldDef_Name(self->fielddef),
935                              TypeInfo_get(self->fielddef), arena);
936   upb_Message_SetFieldByDef(msg, self->fielddef, msgval, arena);
937   return Qnil;
938 }
939 
940 /*
941  * call-seq:
942  *     FieldDescriptor.options => options
943  *
944  * Returns the `FieldOptions` for this `FieldDescriptor`.
945  */
FieldDescriptor_options(VALUE _self)946 static VALUE FieldDescriptor_options(VALUE _self) {
947   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
948   const google_protobuf_FieldOptions* opts =
949       upb_FieldDef_Options(self->fielddef);
950   upb_Arena* arena = upb_Arena_New();
951   size_t size;
952   char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, &size);
953   VALUE field_options = decode_options(_self, "FieldOptions", size, serialized,
954                                        self->descriptor_pool);
955   upb_Arena_Free(arena);
956   return field_options;
957 }
958 
FieldDescriptor_register(VALUE module)959 static void FieldDescriptor_register(VALUE module) {
960   VALUE klass = rb_define_class_under(module, "FieldDescriptor", rb_cObject);
961   rb_define_alloc_func(klass, FieldDescriptor_alloc);
962   rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3);
963   rb_define_method(klass, "name", FieldDescriptor_name, 0);
964   rb_define_method(klass, "type", FieldDescriptor__type, 0);
965   rb_define_method(klass, "default", FieldDescriptor_default, 0);
966   rb_define_method(klass, "has_presence?", FieldDescriptor_has_presence, 0);
967   rb_define_method(klass, "is_packed?", FieldDescriptor_is_packed, 0);
968   rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0);
969   rb_define_method(klass, "label", FieldDescriptor_label, 0);
970   rb_define_method(klass, "number", FieldDescriptor_number, 0);
971   rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
972   rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
973   rb_define_method(klass, "has?", FieldDescriptor_has, 1);
974   rb_define_method(klass, "clear", FieldDescriptor_clear, 1);
975   rb_define_method(klass, "get", FieldDescriptor_get, 1);
976   rb_define_method(klass, "set", FieldDescriptor_set, 2);
977   rb_define_method(klass, "options", FieldDescriptor_options, 0);
978   rb_gc_register_address(&cFieldDescriptor);
979   cFieldDescriptor = klass;
980 }
981 
982 // -----------------------------------------------------------------------------
983 // OneofDescriptor.
984 // -----------------------------------------------------------------------------
985 
986 typedef struct {
987   const upb_OneofDef* oneofdef;
988   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
989   // macro to update VALUE references, as to trigger write barriers.
990   VALUE descriptor_pool;  // Owns the upb_OneofDef.
991 } OneofDescriptor;
992 
993 static VALUE cOneofDescriptor = Qnil;
994 
OneofDescriptor_mark(void * _self)995 static void OneofDescriptor_mark(void* _self) {
996   OneofDescriptor* self = _self;
997   rb_gc_mark(self->descriptor_pool);
998 }
999 
1000 static const rb_data_type_t OneofDescriptor_type = {
1001     "Google::Protobuf::OneofDescriptor",
1002     {OneofDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1003     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1004 };
1005 
ruby_to_OneofDescriptor(VALUE val)1006 static OneofDescriptor* ruby_to_OneofDescriptor(VALUE val) {
1007   OneofDescriptor* ret;
1008   TypedData_Get_Struct(val, OneofDescriptor, &OneofDescriptor_type, ret);
1009   return ret;
1010 }
1011 
1012 /*
1013  * call-seq:
1014  *     OneofDescriptor.new => oneof_descriptor
1015  *
1016  * Creates a new, empty, oneof descriptor. The oneof may only be modified prior
1017  * to being added to a message descriptor which is subsequently added to a pool.
1018  */
OneofDescriptor_alloc(VALUE klass)1019 static VALUE OneofDescriptor_alloc(VALUE klass) {
1020   OneofDescriptor* self = ALLOC(OneofDescriptor);
1021   VALUE ret = TypedData_Wrap_Struct(klass, &OneofDescriptor_type, self);
1022   self->oneofdef = NULL;
1023   self->descriptor_pool = Qnil;
1024   return ret;
1025 }
1026 
1027 /*
1028  * call-seq:
1029  *    OneofDescriptor.new(c_only_cookie, pool, ptr) => OneofDescriptor
1030  *
1031  * Creates a descriptor wrapper object.  May only be called from C.
1032  */
OneofDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)1033 static VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
1034                                         VALUE descriptor_pool, VALUE ptr) {
1035   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1036 
1037   if (cookie != c_only_cookie) {
1038     rb_raise(rb_eRuntimeError,
1039              "Descriptor objects may not be created from Ruby.");
1040   }
1041 
1042   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
1043   self->oneofdef = (const upb_OneofDef*)NUM2ULL(ptr);
1044 
1045   return Qnil;
1046 }
1047 
1048 /*
1049  * call-seq:
1050  *     OneofDescriptor.name => name
1051  *
1052  * Returns the name of this oneof.
1053  */
OneofDescriptor_name(VALUE _self)1054 static VALUE OneofDescriptor_name(VALUE _self) {
1055   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1056   return rb_str_maybe_null(upb_OneofDef_Name(self->oneofdef));
1057 }
1058 
1059 /*
1060  * call-seq:
1061  *     OneofDescriptor.each(&block) => nil
1062  *
1063  * Iterates through fields in this oneof, yielding to the block on each one.
1064  */
OneofDescriptor_each(VALUE _self)1065 static VALUE OneofDescriptor_each(VALUE _self) {
1066   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1067 
1068   int n = upb_OneofDef_FieldCount(self->oneofdef);
1069   for (int i = 0; i < n; i++) {
1070     const upb_FieldDef* f = upb_OneofDef_Field(self->oneofdef, i);
1071     VALUE obj = get_fielddef_obj(self->descriptor_pool, f);
1072     rb_yield(obj);
1073   }
1074   return Qnil;
1075 }
1076 
1077 /*
1078  * call-seq:
1079  *     OneofDescriptor.options => options
1080  *
1081  * Returns the `OneofOptions` for this `OneofDescriptor`.
1082  */
OneOfDescriptor_options(VALUE _self)1083 static VALUE OneOfDescriptor_options(VALUE _self) {
1084   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1085   const google_protobuf_OneofOptions* opts =
1086       upb_OneofDef_Options(self->oneofdef);
1087   upb_Arena* arena = upb_Arena_New();
1088   size_t size;
1089   char* serialized = google_protobuf_OneofOptions_serialize(opts, arena, &size);
1090   VALUE oneof_options = decode_options(_self, "OneofOptions", size, serialized,
1091                                        self->descriptor_pool);
1092   upb_Arena_Free(arena);
1093   return oneof_options;
1094 }
1095 
OneofDescriptor_register(VALUE module)1096 static void OneofDescriptor_register(VALUE module) {
1097   VALUE klass = rb_define_class_under(module, "OneofDescriptor", rb_cObject);
1098   rb_define_alloc_func(klass, OneofDescriptor_alloc);
1099   rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3);
1100   rb_define_method(klass, "name", OneofDescriptor_name, 0);
1101   rb_define_method(klass, "each", OneofDescriptor_each, 0);
1102   rb_define_method(klass, "options", OneOfDescriptor_options, 0);
1103   rb_include_module(klass, rb_mEnumerable);
1104   rb_gc_register_address(&cOneofDescriptor);
1105   cOneofDescriptor = klass;
1106 }
1107 
1108 // -----------------------------------------------------------------------------
1109 // EnumDescriptor.
1110 // -----------------------------------------------------------------------------
1111 
1112 typedef struct {
1113   const upb_EnumDef* enumdef;
1114   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
1115   // macro to update VALUE references, as to trigger write barriers.
1116   VALUE module;           // begins as nil
1117   VALUE descriptor_pool;  // Owns the upb_EnumDef.
1118 } EnumDescriptor;
1119 
1120 static VALUE cEnumDescriptor = Qnil;
1121 
EnumDescriptor_mark(void * _self)1122 static void EnumDescriptor_mark(void* _self) {
1123   EnumDescriptor* self = _self;
1124   rb_gc_mark(self->module);
1125   rb_gc_mark(self->descriptor_pool);
1126 }
1127 
1128 static const rb_data_type_t EnumDescriptor_type = {
1129     "Google::Protobuf::EnumDescriptor",
1130     {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1131     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1132 };
1133 
ruby_to_EnumDescriptor(VALUE val)1134 static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) {
1135   EnumDescriptor* ret;
1136   TypedData_Get_Struct(val, EnumDescriptor, &EnumDescriptor_type, ret);
1137   return ret;
1138 }
1139 
EnumDescriptor_alloc(VALUE klass)1140 static VALUE EnumDescriptor_alloc(VALUE klass) {
1141   EnumDescriptor* self = ALLOC(EnumDescriptor);
1142   VALUE ret = TypedData_Wrap_Struct(klass, &EnumDescriptor_type, self);
1143   self->enumdef = NULL;
1144   self->module = Qnil;
1145   self->descriptor_pool = Qnil;
1146   return ret;
1147 }
1148 
1149 // Exposed to other modules in defs.h.
EnumDescriptor_GetEnumDef(VALUE enum_desc_rb)1150 const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) {
1151   EnumDescriptor* desc = ruby_to_EnumDescriptor(enum_desc_rb);
1152   return desc->enumdef;
1153 }
1154 
1155 /*
1156  * call-seq:
1157  *    EnumDescriptor.new(c_only_cookie, ptr) => EnumDescriptor
1158  *
1159  * Creates a descriptor wrapper object.  May only be called from C.
1160  */
EnumDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)1161 static VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
1162                                        VALUE descriptor_pool, VALUE ptr) {
1163   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1164 
1165   if (cookie != c_only_cookie) {
1166     rb_raise(rb_eRuntimeError,
1167              "Descriptor objects may not be created from Ruby.");
1168   }
1169 
1170   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
1171   self->enumdef = (const upb_EnumDef*)NUM2ULL(ptr);
1172 
1173   return Qnil;
1174 }
1175 
1176 /*
1177  * call-seq:
1178  *    EnumDescriptor.file_descriptor
1179  *
1180  * Returns the FileDescriptor object this enum belongs to.
1181  */
EnumDescriptor_file_descriptor(VALUE _self)1182 static VALUE EnumDescriptor_file_descriptor(VALUE _self) {
1183   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1184   return get_filedef_obj(self->descriptor_pool,
1185                          upb_EnumDef_File(self->enumdef));
1186 }
1187 
1188 /*
1189  * call-seq:
1190  *     EnumDescriptor.is_closed? => bool
1191  *
1192  * Returns whether this enum is open or closed.
1193  */
EnumDescriptor_is_closed(VALUE _self)1194 static VALUE EnumDescriptor_is_closed(VALUE _self) {
1195   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1196   return upb_EnumDef_IsClosed(self->enumdef) ? Qtrue : Qfalse;
1197 }
1198 
1199 /*
1200  * call-seq:
1201  *     EnumDescriptor.name => name
1202  *
1203  * Returns the name of this enum type.
1204  */
EnumDescriptor_name(VALUE _self)1205 static VALUE EnumDescriptor_name(VALUE _self) {
1206   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1207   return rb_str_maybe_null(upb_EnumDef_FullName(self->enumdef));
1208 }
1209 
1210 /*
1211  * call-seq:
1212  *     EnumDescriptor.lookup_name(name) => value
1213  *
1214  * Returns the numeric value corresponding to the given key name (as a Ruby
1215  * symbol), or nil if none.
1216  */
EnumDescriptor_lookup_name(VALUE _self,VALUE name)1217 static VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
1218   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1219   const char* name_str = rb_id2name(SYM2ID(name));
1220   const upb_EnumValueDef* ev =
1221       upb_EnumDef_FindValueByName(self->enumdef, name_str);
1222   if (ev) {
1223     return INT2NUM(upb_EnumValueDef_Number(ev));
1224   } else {
1225     return Qnil;
1226   }
1227 }
1228 
1229 /*
1230  * call-seq:
1231  *     EnumDescriptor.lookup_value(name) => value
1232  *
1233  * Returns the key name (as a Ruby symbol) corresponding to the integer value,
1234  * or nil if none.
1235  */
EnumDescriptor_lookup_value(VALUE _self,VALUE number)1236 static VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
1237   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1238   int32_t val = NUM2INT(number);
1239   const upb_EnumValueDef* ev =
1240       upb_EnumDef_FindValueByNumber(self->enumdef, val);
1241   if (ev) {
1242     return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
1243   } else {
1244     return Qnil;
1245   }
1246 }
1247 
1248 /*
1249  * call-seq:
1250  *     EnumDescriptor.each(&block)
1251  *
1252  * Iterates over key => value mappings in this enum's definition, yielding to
1253  * the block with (key, value) arguments for each one.
1254  */
EnumDescriptor_each(VALUE _self)1255 static VALUE EnumDescriptor_each(VALUE _self) {
1256   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1257 
1258   int n = upb_EnumDef_ValueCount(self->enumdef);
1259   for (int i = 0; i < n; i++) {
1260     const upb_EnumValueDef* ev = upb_EnumDef_Value(self->enumdef, i);
1261     VALUE key = ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
1262     VALUE number = INT2NUM(upb_EnumValueDef_Number(ev));
1263     rb_yield_values(2, key, number);
1264   }
1265 
1266   return Qnil;
1267 }
1268 
1269 /*
1270  * call-seq:
1271  *     EnumDescriptor.enummodule => module
1272  *
1273  * Returns the Ruby module corresponding to this enum type.
1274  */
EnumDescriptor_enummodule(VALUE _self)1275 static VALUE EnumDescriptor_enummodule(VALUE _self) {
1276   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1277   if (self->module == Qnil) {
1278     RB_OBJ_WRITE(_self, &self->module, build_module_from_enumdesc(_self));
1279   }
1280   return self->module;
1281 }
1282 
1283 /*
1284  * call-seq:
1285  *     EnumDescriptor.options => options
1286  *
1287  * Returns the `EnumOptions` for this `EnumDescriptor`.
1288  */
EnumDescriptor_options(VALUE _self)1289 static VALUE EnumDescriptor_options(VALUE _self) {
1290   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1291   const google_protobuf_EnumOptions* opts = upb_EnumDef_Options(self->enumdef);
1292   upb_Arena* arena = upb_Arena_New();
1293   size_t size;
1294   char* serialized = google_protobuf_EnumOptions_serialize(opts, arena, &size);
1295   VALUE enum_options = decode_options(_self, "EnumOptions", size, serialized,
1296                                       self->descriptor_pool);
1297   upb_Arena_Free(arena);
1298   return enum_options;
1299 }
1300 
EnumDescriptor_register(VALUE module)1301 static void EnumDescriptor_register(VALUE module) {
1302   VALUE klass = rb_define_class_under(module, "EnumDescriptor", rb_cObject);
1303   rb_define_alloc_func(klass, EnumDescriptor_alloc);
1304   rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3);
1305   rb_define_method(klass, "name", EnumDescriptor_name, 0);
1306   rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
1307   rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
1308   rb_define_method(klass, "each", EnumDescriptor_each, 0);
1309   rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
1310   rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0);
1311   rb_define_method(klass, "is_closed?", EnumDescriptor_is_closed, 0);
1312   rb_define_method(klass, "options", EnumDescriptor_options, 0);
1313   rb_include_module(klass, rb_mEnumerable);
1314   rb_gc_register_address(&cEnumDescriptor);
1315   cEnumDescriptor = klass;
1316 }
1317 
1318 // -----------------------------------------------------------------------------
1319 // ServiceDescriptor
1320 // -----------------------------------------------------------------------------
1321 
1322 typedef struct {
1323   const upb_ServiceDef* servicedef;
1324   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
1325   // macro to update VALUE references, as to trigger write barriers.
1326   VALUE module;           // begins as nil
1327   VALUE descriptor_pool;  // Owns the upb_ServiceDef.
1328 } ServiceDescriptor;
1329 
1330 static VALUE cServiceDescriptor = Qnil;
1331 
ServiceDescriptor_mark(void * _self)1332 static void ServiceDescriptor_mark(void* _self) {
1333   ServiceDescriptor* self = _self;
1334   rb_gc_mark(self->module);
1335   rb_gc_mark(self->descriptor_pool);
1336 }
1337 
1338 static const rb_data_type_t ServiceDescriptor_type = {
1339     "Google::Protobuf::ServicDescriptor",
1340     {ServiceDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1341     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1342 };
1343 
ruby_to_ServiceDescriptor(VALUE val)1344 static ServiceDescriptor* ruby_to_ServiceDescriptor(VALUE val) {
1345   ServiceDescriptor* ret;
1346   TypedData_Get_Struct(val, ServiceDescriptor, &ServiceDescriptor_type, ret);
1347   return ret;
1348 }
1349 
ServiceDescriptor_alloc(VALUE klass)1350 static VALUE ServiceDescriptor_alloc(VALUE klass) {
1351   ServiceDescriptor* self = ALLOC(ServiceDescriptor);
1352   VALUE ret = TypedData_Wrap_Struct(klass, &ServiceDescriptor_type, self);
1353   self->servicedef = NULL;
1354   self->module = Qnil;
1355   self->descriptor_pool = Qnil;
1356   return ret;
1357 }
1358 
1359 /*
1360  * call-seq:
1361  *    ServiceDescriptor.new(c_only_cookie, ptr) => ServiceDescriptor
1362  *
1363  * Creates a descriptor wrapper object.  May only be called from C.
1364  */
ServiceDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)1365 static VALUE ServiceDescriptor_initialize(VALUE _self, VALUE cookie,
1366                                           VALUE descriptor_pool, VALUE ptr) {
1367   ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1368 
1369   if (cookie != c_only_cookie) {
1370     rb_raise(rb_eRuntimeError,
1371              "Descriptor objects may not be created from Ruby.");
1372   }
1373 
1374   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
1375   self->servicedef = (const upb_ServiceDef*)NUM2ULL(ptr);
1376 
1377   return Qnil;
1378 }
1379 
1380 /*
1381  * call-seq:
1382  *     ServiceDescriptor.name => name
1383  *
1384  * Returns the name of this service.
1385  */
ServiceDescriptor_name(VALUE _self)1386 static VALUE ServiceDescriptor_name(VALUE _self) {
1387   ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1388   return rb_str_maybe_null(upb_ServiceDef_FullName(self->servicedef));
1389 }
1390 
1391 /*
1392  * call-seq:
1393  *    ServiceDescriptor.file_descriptor
1394  *
1395  * Returns the FileDescriptor object this service belongs to.
1396  */
ServiceDescriptor_file_descriptor(VALUE _self)1397 static VALUE ServiceDescriptor_file_descriptor(VALUE _self) {
1398   ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1399   return get_filedef_obj(self->descriptor_pool,
1400                          upb_ServiceDef_File(self->servicedef));
1401 }
1402 
1403 /*
1404  * call-seq:
1405  *     ServiceDescriptor.each(&block)
1406  *
1407  * Iterates over methods in this service, yielding to the block on each one.
1408  */
ServiceDescriptor_each(VALUE _self)1409 static VALUE ServiceDescriptor_each(VALUE _self) {
1410   ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1411 
1412   int n = upb_ServiceDef_MethodCount(self->servicedef);
1413   for (int i = 0; i < n; i++) {
1414     const upb_MethodDef* method = upb_ServiceDef_Method(self->servicedef, i);
1415     VALUE obj = get_methoddef_obj(self->descriptor_pool, method);
1416     rb_yield(obj);
1417   }
1418   return Qnil;
1419 }
1420 
1421 /*
1422  * call-seq:
1423  *     ServiceDescriptor.options => options
1424  *
1425  * Returns the `ServiceOptions` for this `ServiceDescriptor`.
1426  */
ServiceDescriptor_options(VALUE _self)1427 static VALUE ServiceDescriptor_options(VALUE _self) {
1428   ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1429   const google_protobuf_ServiceOptions* opts =
1430       upb_ServiceDef_Options(self->servicedef);
1431   upb_Arena* arena = upb_Arena_New();
1432   size_t size;
1433   char* serialized =
1434       google_protobuf_ServiceOptions_serialize(opts, arena, &size);
1435   VALUE service_options = decode_options(_self, "ServiceOptions", size,
1436                                          serialized, self->descriptor_pool);
1437   upb_Arena_Free(arena);
1438   return service_options;
1439 }
1440 
ServiceDescriptor_register(VALUE module)1441 static void ServiceDescriptor_register(VALUE module) {
1442   VALUE klass = rb_define_class_under(module, "ServiceDescriptor", rb_cObject);
1443   rb_define_alloc_func(klass, ServiceDescriptor_alloc);
1444   rb_define_method(klass, "initialize", ServiceDescriptor_initialize, 3);
1445   rb_define_method(klass, "name", ServiceDescriptor_name, 0);
1446   rb_define_method(klass, "each", ServiceDescriptor_each, 0);
1447   rb_define_method(klass, "file_descriptor", ServiceDescriptor_file_descriptor,
1448                    0);
1449   rb_define_method(klass, "options", ServiceDescriptor_options, 0);
1450   rb_include_module(klass, rb_mEnumerable);
1451   rb_gc_register_address(&cServiceDescriptor);
1452   cServiceDescriptor = klass;
1453 }
1454 
1455 // -----------------------------------------------------------------------------
1456 // MethodDescriptor
1457 // -----------------------------------------------------------------------------
1458 
1459 typedef struct {
1460   const upb_MethodDef* methoddef;
1461   // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
1462   // macro to update VALUE references, as to trigger write barriers.
1463   VALUE module;           // begins as nil
1464   VALUE descriptor_pool;  // Owns the upb_MethodDef.
1465 } MethodDescriptor;
1466 
1467 static VALUE cMethodDescriptor = Qnil;
1468 
MethodDescriptor_mark(void * _self)1469 static void MethodDescriptor_mark(void* _self) {
1470   MethodDescriptor* self = _self;
1471   rb_gc_mark(self->module);
1472   rb_gc_mark(self->descriptor_pool);
1473 }
1474 
1475 static const rb_data_type_t MethodDescriptor_type = {
1476     "Google::Protobuf::MethodDescriptor",
1477     {MethodDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1478     .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1479 };
1480 
ruby_to_MethodDescriptor(VALUE val)1481 static MethodDescriptor* ruby_to_MethodDescriptor(VALUE val) {
1482   MethodDescriptor* ret;
1483   TypedData_Get_Struct(val, MethodDescriptor, &MethodDescriptor_type, ret);
1484   return ret;
1485 }
1486 
MethodDescriptor_alloc(VALUE klass)1487 static VALUE MethodDescriptor_alloc(VALUE klass) {
1488   MethodDescriptor* self = ALLOC(MethodDescriptor);
1489   VALUE ret = TypedData_Wrap_Struct(klass, &MethodDescriptor_type, self);
1490   self->methoddef = NULL;
1491   self->module = Qnil;
1492   self->descriptor_pool = Qnil;
1493   return ret;
1494 }
1495 
1496 /*
1497  * call-seq:
1498  *    MethodDescriptor.new(c_only_cookie, ptr) => MethodDescriptor
1499  *
1500  * Creates a descriptor wrapper object.  May only be called from C.
1501  */
MethodDescriptor_initialize(VALUE _self,VALUE cookie,VALUE descriptor_pool,VALUE ptr)1502 static VALUE MethodDescriptor_initialize(VALUE _self, VALUE cookie,
1503                                          VALUE descriptor_pool, VALUE ptr) {
1504   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1505 
1506   if (cookie != c_only_cookie) {
1507     rb_raise(rb_eRuntimeError,
1508              "Descriptor objects may not be created from Ruby.");
1509   }
1510 
1511   RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
1512   self->methoddef = (const upb_MethodDef*)NUM2ULL(ptr);
1513 
1514   return Qnil;
1515 }
1516 
1517 /*
1518  * call-seq:
1519  *     MethodDescriptor.name => name
1520  *
1521  * Returns the name of this method
1522  */
MethodDescriptor_name(VALUE _self)1523 static VALUE MethodDescriptor_name(VALUE _self) {
1524   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1525   return rb_str_maybe_null(upb_MethodDef_Name(self->methoddef));
1526 }
1527 
1528 /*
1529  * call-seq:
1530  *     MethodDescriptor.options => options
1531  *
1532  * Returns the `MethodOptions` for this `MethodDescriptor`.
1533  */
MethodDescriptor_options(VALUE _self)1534 static VALUE MethodDescriptor_options(VALUE _self) {
1535   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1536   const google_protobuf_MethodOptions* opts =
1537       upb_MethodDef_Options(self->methoddef);
1538   upb_Arena* arena = upb_Arena_New();
1539   size_t size;
1540   char* serialized =
1541       google_protobuf_MethodOptions_serialize(opts, arena, &size);
1542   VALUE method_options = decode_options(_self, "MethodOptions", size,
1543                                         serialized, self->descriptor_pool);
1544   upb_Arena_Free(arena);
1545   return method_options;
1546 }
1547 
1548 /*
1549  * call-seq:
1550  *      MethodDescriptor.input_type => Descriptor
1551  *
1552  * Returns the `Descriptor` for the request message type of this method
1553  */
MethodDescriptor_input_type(VALUE _self)1554 static VALUE MethodDescriptor_input_type(VALUE _self) {
1555   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1556   const upb_MessageDef* type = upb_MethodDef_InputType(self->methoddef);
1557   return get_msgdef_obj(self->descriptor_pool, type);
1558 }
1559 
1560 /*
1561  * call-seq:
1562  *      MethodDescriptor.output_type => Descriptor
1563  *
1564  * Returns the `Descriptor` for the response message type of this method
1565  */
MethodDescriptor_output_type(VALUE _self)1566 static VALUE MethodDescriptor_output_type(VALUE _self) {
1567   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1568   const upb_MessageDef* type = upb_MethodDef_OutputType(self->methoddef);
1569   return get_msgdef_obj(self->descriptor_pool, type);
1570 }
1571 
1572 /*
1573  * call-seq:
1574  *      MethodDescriptor.client_streaming => bool
1575  *
1576  * Returns whether or not this is a streaming request method
1577  */
MethodDescriptor_client_streaming(VALUE _self)1578 static VALUE MethodDescriptor_client_streaming(VALUE _self) {
1579   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1580   return upb_MethodDef_ClientStreaming(self->methoddef) ? Qtrue : Qfalse;
1581 }
1582 
1583 /*
1584  * call-seq:
1585  *      MethodDescriptor.server_streaming => bool
1586  *
1587  * Returns whether or not this is a streaming response method
1588  */
MethodDescriptor_server_streaming(VALUE _self)1589 static VALUE MethodDescriptor_server_streaming(VALUE _self) {
1590   MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1591   return upb_MethodDef_ServerStreaming(self->methoddef) ? Qtrue : Qfalse;
1592 }
1593 
MethodDescriptor_register(VALUE module)1594 static void MethodDescriptor_register(VALUE module) {
1595   VALUE klass = rb_define_class_under(module, "MethodDescriptor", rb_cObject);
1596   rb_define_alloc_func(klass, MethodDescriptor_alloc);
1597   rb_define_method(klass, "initialize", MethodDescriptor_initialize, 3);
1598   rb_define_method(klass, "name", MethodDescriptor_name, 0);
1599   rb_define_method(klass, "options", MethodDescriptor_options, 0);
1600   rb_define_method(klass, "input_type", MethodDescriptor_input_type, 0);
1601   rb_define_method(klass, "output_type", MethodDescriptor_output_type, 0);
1602   rb_define_method(klass, "client_streaming", MethodDescriptor_client_streaming,
1603                    0);
1604   rb_define_method(klass, "server_streaming", MethodDescriptor_server_streaming,
1605                    0);
1606   rb_gc_register_address(&cMethodDescriptor);
1607   cMethodDescriptor = klass;
1608 }
1609 
get_def_obj(VALUE _descriptor_pool,const void * ptr,VALUE klass)1610 static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
1611   DescriptorPool* descriptor_pool = ruby_to_DescriptorPool(_descriptor_pool);
1612   VALUE key = ULL2NUM((intptr_t)ptr);
1613   VALUE def;
1614 
1615   def = rb_hash_aref(descriptor_pool->def_to_descriptor, key);
1616 
1617   if (ptr == NULL) {
1618     return Qnil;
1619   }
1620 
1621   if (def == Qnil) {
1622     // Lazily create wrapper object.
1623     VALUE args[3] = {c_only_cookie, _descriptor_pool, key};
1624     def = rb_class_new_instance(3, args, klass);
1625     rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
1626   }
1627 
1628   return def;
1629 }
1630 
get_msgdef_obj(VALUE descriptor_pool,const upb_MessageDef * def)1631 static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def) {
1632   return get_def_obj(descriptor_pool, def, cDescriptor);
1633 }
1634 
get_enumdef_obj(VALUE descriptor_pool,const upb_EnumDef * def)1635 static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def) {
1636   return get_def_obj(descriptor_pool, def, cEnumDescriptor);
1637 }
1638 
get_fielddef_obj(VALUE descriptor_pool,const upb_FieldDef * def)1639 static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def) {
1640   return get_def_obj(descriptor_pool, def, cFieldDescriptor);
1641 }
1642 
get_filedef_obj(VALUE descriptor_pool,const upb_FileDef * def)1643 static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def) {
1644   return get_def_obj(descriptor_pool, def, cFileDescriptor);
1645 }
1646 
get_oneofdef_obj(VALUE descriptor_pool,const upb_OneofDef * def)1647 static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def) {
1648   return get_def_obj(descriptor_pool, def, cOneofDescriptor);
1649 }
1650 
get_servicedef_obj(VALUE descriptor_pool,const upb_ServiceDef * def)1651 static VALUE get_servicedef_obj(VALUE descriptor_pool,
1652                                 const upb_ServiceDef* def) {
1653   return get_def_obj(descriptor_pool, def, cServiceDescriptor);
1654 }
1655 
get_methoddef_obj(VALUE descriptor_pool,const upb_MethodDef * def)1656 static VALUE get_methoddef_obj(VALUE descriptor_pool,
1657                                const upb_MethodDef* def) {
1658   return get_def_obj(descriptor_pool, def, cMethodDescriptor);
1659 }
1660 
1661 // -----------------------------------------------------------------------------
1662 // Shared functions
1663 // -----------------------------------------------------------------------------
1664 
1665 // Functions exposed to other modules in defs.h.
1666 
Descriptor_DefToClass(const upb_MessageDef * m)1667 VALUE Descriptor_DefToClass(const upb_MessageDef* m) {
1668   const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
1669   VALUE pool = ObjectCache_Get(symtab);
1670   PBRUBY_ASSERT(pool != Qnil);
1671   VALUE desc_rb = get_msgdef_obj(pool, m);
1672   const Descriptor* desc = ruby_to_Descriptor(desc_rb);
1673   return desc->klass;
1674 }
1675 
Descriptor_GetMsgDef(VALUE desc_rb)1676 const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb) {
1677   const Descriptor* desc = ruby_to_Descriptor(desc_rb);
1678   return desc->msgdef;
1679 }
1680 
TypeInfo_InitArg(int argc,VALUE * argv,int skip_arg)1681 VALUE TypeInfo_InitArg(int argc, VALUE* argv, int skip_arg) {
1682   if (argc > skip_arg) {
1683     if (argc > 1 + skip_arg) {
1684       rb_raise(rb_eArgError, "Expected a maximum of %d arguments.",
1685                skip_arg + 1);
1686     }
1687     return argv[skip_arg];
1688   } else {
1689     return Qnil;
1690   }
1691 }
1692 
TypeInfo_FromClass(int argc,VALUE * argv,int skip_arg,VALUE * type_class,VALUE * init_arg)1693 TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg,
1694                             VALUE* type_class, VALUE* init_arg) {
1695   TypeInfo ret = {ruby_to_fieldtype(argv[skip_arg])};
1696 
1697   if (ret.type == kUpb_CType_Message || ret.type == kUpb_CType_Enum) {
1698     *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 2);
1699 
1700     if (argc < 2 + skip_arg) {
1701       rb_raise(rb_eArgError, "Expected at least %d arguments for message/enum.",
1702                2 + skip_arg);
1703     }
1704 
1705     VALUE klass = argv[1 + skip_arg];
1706     VALUE desc = MessageOrEnum_GetDescriptor(klass);
1707     *type_class = klass;
1708 
1709     if (desc == Qnil) {
1710       rb_raise(rb_eArgError,
1711                "Type class has no descriptor. Please pass a "
1712                "class or enum as returned by the DescriptorPool.");
1713     }
1714 
1715     if (ret.type == kUpb_CType_Message) {
1716       ret.def.msgdef = ruby_to_Descriptor(desc)->msgdef;
1717       Message_CheckClass(klass);
1718     } else {
1719       PBRUBY_ASSERT(ret.type == kUpb_CType_Enum);
1720       ret.def.enumdef = ruby_to_EnumDescriptor(desc)->enumdef;
1721     }
1722   } else {
1723     *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 1);
1724   }
1725 
1726   return ret;
1727 }
1728 
Defs_register(VALUE module)1729 void Defs_register(VALUE module) {
1730   DescriptorPool_register(module);
1731   Descriptor_register(module);
1732   FileDescriptor_register(module);
1733   FieldDescriptor_register(module);
1734   OneofDescriptor_register(module);
1735   EnumDescriptor_register(module);
1736   ServiceDescriptor_register(module);
1737   MethodDescriptor_register(module);
1738 
1739   rb_gc_register_address(&c_only_cookie);
1740   c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
1741 }
1742