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