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