blob: 992f54bc4d612f09fad5e3961dc3c77b6ca26454 [file] [log] [blame]
Chris Fallin973f4252014-11-18 14:19:58 -08001// 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
Joshua Haberman63f324a2019-08-14 22:41:37 +010031#include <ctype.h>
32#include <errno.h>
Joshua Haberman9abf6e22021-01-13 12:16:25 -080033#include <ruby/version.h>
34
35#include "convert.h"
36#include "message.h"
Chris Fallin973f4252014-11-18 14:19:58 -080037#include "protobuf.h"
38
Joshua Haberman9abf6e22021-01-13 12:16:25 -080039static VALUE Builder_build(VALUE _self);
40
41static VALUE cMessageBuilderContext;
42static VALUE cOneofBuilderContext;
43static VALUE cEnumBuilderContext;
44static VALUE cBuilder;
45
46// -----------------------------------------------------------------------------
47// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
48// instances.
49// -----------------------------------------------------------------------------
50
51static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def);
52static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def);
53static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def);
54static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def);
55static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def);
56
57// A distinct object that is not accessible from Ruby. We use this as a
58// constructor argument to enforce that certain objects cannot be created from
59// Ruby.
60VALUE c_only_cookie = Qnil;
61
Chris Fallin973f4252014-11-18 14:19:58 -080062// -----------------------------------------------------------------------------
63// Common utilities.
64// -----------------------------------------------------------------------------
65
Chris Fallin973f4252014-11-18 14:19:58 -080066static const char* get_str(VALUE str) {
67 Check_Type(str, T_STRING);
68 return RSTRING_PTR(str);
69}
70
71static VALUE rb_str_maybe_null(const char* s) {
72 if (s == NULL) {
73 s = "";
74 }
75 return rb_str_new2(s);
76}
77
Joshua Haberman9abf6e22021-01-13 12:16:25 -080078// -----------------------------------------------------------------------------
79// Backward compatibility code.
80// -----------------------------------------------------------------------------
81
Joshua Haberman63f324a2019-08-14 22:41:37 +010082static void rewrite_enum_default(const upb_symtab* symtab,
83 google_protobuf_FileDescriptorProto* file,
84 google_protobuf_FieldDescriptorProto* field) {
85 upb_strview defaultval;
86 const char *type_name_str;
87 char *end;
88 long val;
89 const upb_enumdef *e;
90 upb_strview type_name;
91
92 /* Look for TYPE_ENUM fields that have a default. */
93 if (google_protobuf_FieldDescriptorProto_type(field) !=
94 google_protobuf_FieldDescriptorProto_TYPE_ENUM ||
95 !google_protobuf_FieldDescriptorProto_has_default_value(field) ||
96 !google_protobuf_FieldDescriptorProto_has_type_name(field)) {
97 return;
Chris Fallin973f4252014-11-18 14:19:58 -080098 }
Joshua Haberman63f324a2019-08-14 22:41:37 +010099
100 defaultval = google_protobuf_FieldDescriptorProto_default_value(field);
101 type_name = google_protobuf_FieldDescriptorProto_type_name(field);
102
103 if (defaultval.size == 0 || !isdigit(defaultval.data[0])) {
104 return;
105 }
106
107 if (type_name.size == 0 || type_name.data[0] != '.') {
108 return;
109 }
110
111 type_name_str = type_name.data + 1;
112
113 errno = 0;
114 val = strtol(defaultval.data, &end, 10);
115
116 if (errno != 0 || *end != 0 || val < INT32_MIN || val > INT32_MAX) {
117 return;
118 }
119
120 /* Now find the corresponding enum definition. */
121 e = upb_symtab_lookupenum(symtab, type_name_str);
122 if (e) {
123 /* Look in previously loaded files. */
124 const char *label = upb_enumdef_iton(e, val);
125 if (!label) {
126 return;
127 }
128 google_protobuf_FieldDescriptorProto_set_default_value(
129 field, upb_strview_makez(label));
130 } else {
131 /* Look in enums defined in this file. */
132 const google_protobuf_EnumDescriptorProto* matching_enum = NULL;
133 size_t i, n;
134 const google_protobuf_EnumDescriptorProto* const* enums =
135 google_protobuf_FileDescriptorProto_enum_type(file, &n);
136 const google_protobuf_EnumValueDescriptorProto* const* values;
137
138 for (i = 0; i < n; i++) {
139 if (upb_strview_eql(google_protobuf_EnumDescriptorProto_name(enums[i]),
140 upb_strview_makez(type_name_str))) {
141 matching_enum = enums[i];
142 break;
143 }
144 }
145
146 if (!matching_enum) {
147 return;
148 }
149
150 values = google_protobuf_EnumDescriptorProto_value(matching_enum, &n);
151 for (i = 0; i < n; i++) {
152 if (google_protobuf_EnumValueDescriptorProto_number(values[i]) == val) {
153 google_protobuf_FieldDescriptorProto_set_default_value(
154 field, google_protobuf_EnumValueDescriptorProto_name(values[i]));
155 return;
156 }
157 }
158
159 /* We failed to find an enum default. But we'll just leave the enum
160 * untouched and let the normal def-building code catch it. */
161 }
Chris Fallin973f4252014-11-18 14:19:58 -0800162}
163
Joshua Haberman63f324a2019-08-14 22:41:37 +0100164/* Historically we allowed enum defaults to be specified as a number. In
165 * retrospect this was a mistake as descriptors require defaults to be
166 * specified as a label. This can make a difference if multiple labels have the
167 * same number.
168 *
169 * Here we do a pass over all enum defaults and rewrite numeric defaults by
Brian Wignalla104dff2020-01-08 13:18:20 -0500170 * looking up their labels. This is complicated by the fact that the enum
Joshua Haberman63f324a2019-08-14 22:41:37 +0100171 * definition can live in either the symtab or the file_proto.
172 * */
173static void rewrite_enum_defaults(
174 const upb_symtab* symtab, google_protobuf_FileDescriptorProto* file_proto) {
175 size_t i, n;
176 google_protobuf_DescriptorProto** msgs =
177 google_protobuf_FileDescriptorProto_mutable_message_type(file_proto, &n);
178
179 for (i = 0; i < n; i++) {
180 size_t j, m;
181 google_protobuf_FieldDescriptorProto** fields =
182 google_protobuf_DescriptorProto_mutable_field(msgs[i], &m);
183 for (j = 0; j < m; j++) {
184 rewrite_enum_default(symtab, file_proto, fields[j]);
185 }
186 }
Chris Fallin973f4252014-11-18 14:19:58 -0800187}
188
Joshua Haberman63f324a2019-08-14 22:41:37 +0100189static void remove_path(upb_strview *name) {
190 const char* last = strrchr(name->data, '.');
191 if (last) {
192 size_t remove = last - name->data + 1;
193 name->data += remove;
194 name->size -= remove;
195 }
Chris Fallin973f4252014-11-18 14:19:58 -0800196}
197
Joshua Haberman63f324a2019-08-14 22:41:37 +0100198static void rewrite_nesting(VALUE msg_ent, google_protobuf_DescriptorProto* msg,
199 google_protobuf_DescriptorProto* const* msgs,
200 google_protobuf_EnumDescriptorProto* const* enums,
201 upb_arena *arena) {
202 VALUE submsgs = rb_hash_aref(msg_ent, ID2SYM(rb_intern("msgs")));
203 VALUE enum_pos = rb_hash_aref(msg_ent, ID2SYM(rb_intern("enums")));
204 int submsg_count;
205 int enum_count;
206 int i;
207 google_protobuf_DescriptorProto** msg_msgs;
208 google_protobuf_EnumDescriptorProto** msg_enums;
209
210 Check_Type(submsgs, T_ARRAY);
211 Check_Type(enum_pos, T_ARRAY);
212
213 submsg_count = RARRAY_LEN(submsgs);
214 enum_count = RARRAY_LEN(enum_pos);
215
216 msg_msgs = google_protobuf_DescriptorProto_resize_nested_type(
217 msg, submsg_count, arena);
218 msg_enums =
219 google_protobuf_DescriptorProto_resize_enum_type(msg, enum_count, arena);
220
221 for (i = 0; i < submsg_count; i++) {
222 VALUE submsg_ent = RARRAY_PTR(submsgs)[i];
223 VALUE pos = rb_hash_aref(submsg_ent, ID2SYM(rb_intern("pos")));
224 upb_strview name;
225
226 msg_msgs[i] = msgs[NUM2INT(pos)];
227 name = google_protobuf_DescriptorProto_name(msg_msgs[i]);
228 remove_path(&name);
229 google_protobuf_DescriptorProto_set_name(msg_msgs[i], name);
230 rewrite_nesting(submsg_ent, msg_msgs[i], msgs, enums, arena);
231 }
232
233 for (i = 0; i < enum_count; i++) {
234 VALUE pos = RARRAY_PTR(enum_pos)[i];
235 msg_enums[i] = enums[NUM2INT(pos)];
236 }
Chris Fallinfcd88892015-01-13 18:14:39 -0800237}
238
Joshua Haberman9abf6e22021-01-13 12:16:25 -0800239// -----------------------------------------------------------------------------
240// DescriptorPool.
241// -----------------------------------------------------------------------------
242
243typedef struct {
244 VALUE def_to_descriptor; // Hash table of def* -> Ruby descriptor.
245 upb_symtab* symtab;
246} DescriptorPool;
247
248VALUE cDescriptorPool = Qnil;
249
250// Global singleton DescriptorPool. The user is free to create others, but this
251// is used by generated code.
252VALUE generated_pool = Qnil;
253
254static void DescriptorPool_mark(void* _self) {
255 DescriptorPool* self = _self;
256 rb_gc_mark(self->def_to_descriptor);
257}
258
259static void DescriptorPool_free(void* _self) {
260 DescriptorPool* self = _self;
261 upb_symtab_free(self->symtab);
262 xfree(self);
263}
264
265static const rb_data_type_t DescriptorPool_type = {
266 "Google::Protobuf::DescriptorPool",
267 {DescriptorPool_mark, DescriptorPool_free, NULL},
268 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
269};
270
271static DescriptorPool* ruby_to_DescriptorPool(VALUE val) {
272 DescriptorPool* ret;
273 TypedData_Get_Struct(val, DescriptorPool, &DescriptorPool_type, ret);
274 return ret;
275}
276
277// Exposed to other modules in defs.h.
278const upb_symtab *DescriptorPool_GetSymtab(VALUE desc_pool_rb) {
279 DescriptorPool *pool = ruby_to_DescriptorPool(desc_pool_rb);
280 return pool->symtab;
281}
282
283/*
284 * call-seq:
285 * DescriptorPool.new => pool
286 *
287 * Creates a new, empty, descriptor pool.
288 */
289static VALUE DescriptorPool_alloc(VALUE klass) {
290 DescriptorPool* self = ALLOC(DescriptorPool);
291 VALUE ret;
292
293 self->def_to_descriptor = Qnil;
294 ret = TypedData_Wrap_Struct(klass, &DescriptorPool_type, self);
295
296 self->def_to_descriptor = rb_hash_new();
297 self->symtab = upb_symtab_new();
Joshua Haberman9879f422021-02-24 16:41:35 -0800298 ObjectCache_Add(self->symtab, ret);
Joshua Haberman9abf6e22021-01-13 12:16:25 -0800299
300 return ret;
301}
302
303/*
304 * call-seq:
305 * DescriptorPool.build(&block)
306 *
307 * Invokes the block with a Builder instance as self. All message and enum types
308 * added within the block are committed to the pool atomically, and may refer
309 * (co)recursively to each other. The user should call Builder#add_message and
310 * Builder#add_enum within the block as appropriate. This is the recommended,
311 * idiomatic way to define new message and enum types.
312 */
313static VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self) {
314 VALUE ctx = rb_class_new_instance(1, &_self, cBuilder);
315 VALUE block = rb_block_proc();
316 rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
317 Builder_build(ctx);
318 return Qnil;
319}
320
321/*
322 * call-seq:
323 * DescriptorPool.lookup(name) => descriptor
324 *
325 * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
326 * exists with the given name.
327 */
328static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
329 DescriptorPool* self = ruby_to_DescriptorPool(_self);
330 const char* name_str = get_str(name);
331 const upb_msgdef* msgdef;
332 const upb_enumdef* enumdef;
333
334 msgdef = upb_symtab_lookupmsg(self->symtab, name_str);
335 if (msgdef) {
336 return get_msgdef_obj(_self, msgdef);
337 }
338
339 enumdef = upb_symtab_lookupenum(self->symtab, name_str);
340 if (enumdef) {
341 return get_enumdef_obj(_self, enumdef);
342 }
343
344 return Qnil;
345}
346
347/*
348 * call-seq:
349 * DescriptorPool.generated_pool => descriptor_pool
350 *
351 * Class method that returns the global DescriptorPool. This is a singleton into
352 * which generated-code message and enum types are registered. The user may also
353 * register types in this pool for convenience so that they do not have to hold
354 * a reference to a private pool instance.
355 */
356static VALUE DescriptorPool_generated_pool(VALUE _self) {
357 return generated_pool;
358}
359
360static void DescriptorPool_register(VALUE module) {
361 VALUE klass = rb_define_class_under(
362 module, "DescriptorPool", rb_cObject);
363 rb_define_alloc_func(klass, DescriptorPool_alloc);
364 rb_define_method(klass, "build", DescriptorPool_build, -1);
365 rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
366 rb_define_singleton_method(klass, "generated_pool",
367 DescriptorPool_generated_pool, 0);
368 rb_gc_register_address(&cDescriptorPool);
369 cDescriptorPool = klass;
370
371 rb_gc_register_address(&generated_pool);
372 generated_pool = rb_class_new_instance(0, NULL, klass);
373}
374
375// -----------------------------------------------------------------------------
376// Descriptor.
377// -----------------------------------------------------------------------------
378
379typedef struct {
380 const upb_msgdef* msgdef;
381 VALUE klass;
382 VALUE descriptor_pool;
383} Descriptor;
384
385VALUE cDescriptor = Qnil;
386
387static void Descriptor_mark(void* _self) {
388 Descriptor* self = _self;
389 rb_gc_mark(self->klass);
390 rb_gc_mark(self->descriptor_pool);
391}
392
393static const rb_data_type_t Descriptor_type = {
394 "Google::Protobuf::Descriptor",
395 {Descriptor_mark, RUBY_DEFAULT_FREE, NULL},
396 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
397};
398
399static Descriptor* ruby_to_Descriptor(VALUE val) {
400 Descriptor* ret;
401 TypedData_Get_Struct(val, Descriptor, &Descriptor_type, ret);
402 return ret;
403}
404
405/*
406 * call-seq:
407 * Descriptor.new => descriptor
408 *
409 * Creates a new, empty, message type descriptor. At a minimum, its name must be
410 * set before it is added to a pool. It cannot be used to create messages until
411 * it is added to a pool, after which it becomes immutable (as part of a
412 * finalization process).
413 */
414static VALUE Descriptor_alloc(VALUE klass) {
415 Descriptor* self = ALLOC(Descriptor);
416 VALUE ret = TypedData_Wrap_Struct(klass, &Descriptor_type, self);
417 self->msgdef = NULL;
418 self->klass = Qnil;
419 self->descriptor_pool = Qnil;
420 return ret;
421}
422
423/*
424 * call-seq:
425 * Descriptor.new(c_only_cookie, ptr) => Descriptor
426 *
427 * Creates a descriptor wrapper object. May only be called from C.
428 */
429static VALUE Descriptor_initialize(VALUE _self, VALUE cookie,
430 VALUE descriptor_pool, VALUE ptr) {
431 Descriptor* self = ruby_to_Descriptor(_self);
432
433 if (cookie != c_only_cookie) {
434 rb_raise(rb_eRuntimeError,
435 "Descriptor objects may not be created from Ruby.");
436 }
437
438 self->descriptor_pool = descriptor_pool;
439 self->msgdef = (const upb_msgdef*)NUM2ULL(ptr);
440
441 return Qnil;
442}
443
444/*
445 * call-seq:
446 * Descriptor.file_descriptor
447 *
448 * Returns the FileDescriptor object this message belongs to.
449 */
450static VALUE Descriptor_file_descriptor(VALUE _self) {
451 Descriptor* self = ruby_to_Descriptor(_self);
452 return get_filedef_obj(self->descriptor_pool, upb_msgdef_file(self->msgdef));
453}
454
455/*
456 * call-seq:
457 * Descriptor.name => name
458 *
459 * Returns the name of this message type as a fully-qualified string (e.g.,
460 * My.Package.MessageType).
461 */
462static VALUE Descriptor_name(VALUE _self) {
463 Descriptor* self = ruby_to_Descriptor(_self);
464 return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef));
465}
466
467/*
468 * call-seq:
469 * Descriptor.each(&block)
470 *
471 * Iterates over fields in this message type, yielding to the block on each one.
472 */
473static VALUE Descriptor_each(VALUE _self) {
474 Descriptor* self = ruby_to_Descriptor(_self);
475
476 upb_msg_field_iter it;
477 for (upb_msg_field_begin(&it, self->msgdef);
478 !upb_msg_field_done(&it);
479 upb_msg_field_next(&it)) {
480 const upb_fielddef* field = upb_msg_iter_field(&it);
481 VALUE obj = get_fielddef_obj(self->descriptor_pool, field);
482 rb_yield(obj);
483 }
484 return Qnil;
485}
486
487/*
488 * call-seq:
489 * Descriptor.lookup(name) => FieldDescriptor
490 *
491 * Returns the field descriptor for the field with the given name, if present,
492 * or nil if none.
493 */
494static VALUE Descriptor_lookup(VALUE _self, VALUE name) {
495 Descriptor* self = ruby_to_Descriptor(_self);
496 const char* s = get_str(name);
497 const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
498 if (field == NULL) {
499 return Qnil;
500 }
501 return get_fielddef_obj(self->descriptor_pool, field);
502}
503
504/*
505 * call-seq:
506 * Descriptor.each_oneof(&block) => nil
507 *
508 * Invokes the given block for each oneof in this message type, passing the
509 * corresponding OneofDescriptor.
510 */
511static VALUE Descriptor_each_oneof(VALUE _self) {
512 Descriptor* self = ruby_to_Descriptor(_self);
513
514 upb_msg_oneof_iter it;
515 for (upb_msg_oneof_begin(&it, self->msgdef);
516 !upb_msg_oneof_done(&it);
517 upb_msg_oneof_next(&it)) {
518 const upb_oneofdef* oneof = upb_msg_iter_oneof(&it);
519 VALUE obj = get_oneofdef_obj(self->descriptor_pool, oneof);
520 rb_yield(obj);
521 }
522 return Qnil;
523}
524
525/*
526 * call-seq:
527 * Descriptor.lookup_oneof(name) => OneofDescriptor
528 *
529 * Returns the oneof descriptor for the oneof with the given name, if present,
530 * or nil if none.
531 */
532static VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
533 Descriptor* self = ruby_to_Descriptor(_self);
534 const char* s = get_str(name);
535 const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
536 if (oneof == NULL) {
537 return Qnil;
538 }
539 return get_oneofdef_obj(self->descriptor_pool, oneof);
540}
541
542/*
543 * call-seq:
544 * Descriptor.msgclass => message_klass
545 *
546 * Returns the Ruby class created for this message type.
547 */
548static VALUE Descriptor_msgclass(VALUE _self) {
549 Descriptor* self = ruby_to_Descriptor(_self);
550 if (self->klass == Qnil) {
551 self->klass = build_class_from_descriptor(_self);
552 }
553 return self->klass;
554}
555
556static void Descriptor_register(VALUE module) {
557 VALUE klass = rb_define_class_under(
558 module, "Descriptor", rb_cObject);
559 rb_define_alloc_func(klass, Descriptor_alloc);
560 rb_define_method(klass, "initialize", Descriptor_initialize, 3);
561 rb_define_method(klass, "each", Descriptor_each, 0);
562 rb_define_method(klass, "lookup", Descriptor_lookup, 1);
563 rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
564 rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
565 rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
566 rb_define_method(klass, "name", Descriptor_name, 0);
567 rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0);
568 rb_include_module(klass, rb_mEnumerable);
569 rb_gc_register_address(&cDescriptor);
570 cDescriptor = klass;
571}
572
573// -----------------------------------------------------------------------------
574// FileDescriptor.
575// -----------------------------------------------------------------------------
576
577typedef struct {
578 const upb_filedef* filedef;
579 VALUE descriptor_pool; // Owns the upb_filedef.
580} FileDescriptor;
581
582static VALUE cFileDescriptor = Qnil;
583
584static void FileDescriptor_mark(void* _self) {
585 FileDescriptor* self = _self;
586 rb_gc_mark(self->descriptor_pool);
587}
588
589static const rb_data_type_t FileDescriptor_type = {
590 "Google::Protobuf::FileDescriptor",
591 {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
592 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
593};
594
595static FileDescriptor* ruby_to_FileDescriptor(VALUE val) {
596 FileDescriptor* ret;
597 TypedData_Get_Struct(val, FileDescriptor, &FileDescriptor_type, ret);
598 return ret;
599}
600
601static VALUE FileDescriptor_alloc(VALUE klass) {
602 FileDescriptor* self = ALLOC(FileDescriptor);
603 VALUE ret = TypedData_Wrap_Struct(klass, &FileDescriptor_type, self);
604 self->descriptor_pool = Qnil;
605 self->filedef = NULL;
606 return ret;
607}
608
609/*
610 * call-seq:
611 * FileDescriptor.new => file
612 *
613 * Returns a new file descriptor. The syntax must be set before it's passed
614 * to a builder.
615 */
616static VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
617 VALUE descriptor_pool, VALUE ptr) {
618 FileDescriptor* self = ruby_to_FileDescriptor(_self);
619
620 if (cookie != c_only_cookie) {
621 rb_raise(rb_eRuntimeError,
622 "Descriptor objects may not be created from Ruby.");
623 }
624
625 self->descriptor_pool = descriptor_pool;
626 self->filedef = (const upb_filedef*)NUM2ULL(ptr);
627
628 return Qnil;
629}
630
631/*
632 * call-seq:
633 * FileDescriptor.name => name
634 *
635 * Returns the name of the file.
636 */
637static VALUE FileDescriptor_name(VALUE _self) {
638 FileDescriptor* self = ruby_to_FileDescriptor(_self);
639 const char* name = upb_filedef_name(self->filedef);
640 return name == NULL ? Qnil : rb_str_new2(name);
641}
642
643/*
644 * call-seq:
645 * FileDescriptor.syntax => syntax
646 *
647 * Returns this file descriptors syntax.
648 *
649 * Valid syntax versions are:
650 * :proto2 or :proto3.
651 */
652static VALUE FileDescriptor_syntax(VALUE _self) {
653 FileDescriptor* self = ruby_to_FileDescriptor(_self);
654
655 switch (upb_filedef_syntax(self->filedef)) {
656 case UPB_SYNTAX_PROTO3: return ID2SYM(rb_intern("proto3"));
657 case UPB_SYNTAX_PROTO2: return ID2SYM(rb_intern("proto2"));
658 default: return Qnil;
659 }
660}
661
662static void FileDescriptor_register(VALUE module) {
663 VALUE klass = rb_define_class_under(
664 module, "FileDescriptor", rb_cObject);
665 rb_define_alloc_func(klass, FileDescriptor_alloc);
666 rb_define_method(klass, "initialize", FileDescriptor_initialize, 3);
667 rb_define_method(klass, "name", FileDescriptor_name, 0);
668 rb_define_method(klass, "syntax", FileDescriptor_syntax, 0);
669 rb_gc_register_address(&cFileDescriptor);
670 cFileDescriptor = klass;
671}
672
673// -----------------------------------------------------------------------------
674// FieldDescriptor.
675// -----------------------------------------------------------------------------
676
677typedef struct {
678 const upb_fielddef* fielddef;
679 VALUE descriptor_pool; // Owns the upb_fielddef.
680} FieldDescriptor;
681
682static VALUE cFieldDescriptor = Qnil;
683
684static void FieldDescriptor_mark(void* _self) {
685 FieldDescriptor* self = _self;
686 rb_gc_mark(self->descriptor_pool);
687}
688
689static const rb_data_type_t FieldDescriptor_type = {
690 "Google::Protobuf::FieldDescriptor",
691 {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
692 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
693};
694
695static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) {
696 FieldDescriptor* ret;
697 TypedData_Get_Struct(val, FieldDescriptor, &FieldDescriptor_type, ret);
698 return ret;
699}
700
701/*
702 * call-seq:
703 * FieldDescriptor.new => field
704 *
705 * Returns a new field descriptor. Its name, type, etc. must be set before it is
706 * added to a message type.
707 */
708static VALUE FieldDescriptor_alloc(VALUE klass) {
709 FieldDescriptor* self = ALLOC(FieldDescriptor);
710 VALUE ret = TypedData_Wrap_Struct(klass, &FieldDescriptor_type, self);
711 self->fielddef = NULL;
712 return ret;
713}
714
715/*
716 * call-seq:
717 * EnumDescriptor.new(c_only_cookie, pool, ptr) => EnumDescriptor
718 *
719 * Creates a descriptor wrapper object. May only be called from C.
720 */
721static VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
722 VALUE descriptor_pool, VALUE ptr) {
723 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
724
725 if (cookie != c_only_cookie) {
726 rb_raise(rb_eRuntimeError,
727 "Descriptor objects may not be created from Ruby.");
728 }
729
730 self->descriptor_pool = descriptor_pool;
731 self->fielddef = (const upb_fielddef*)NUM2ULL(ptr);
732
733 return Qnil;
734}
735
736/*
737 * call-seq:
738 * FieldDescriptor.name => name
739 *
740 * Returns the name of this field.
741 */
742static VALUE FieldDescriptor_name(VALUE _self) {
743 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
744 return rb_str_maybe_null(upb_fielddef_name(self->fielddef));
745}
746
747// Non-static, exposed to other .c files.
748upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
749 if (TYPE(type) != T_SYMBOL) {
750 rb_raise(rb_eArgError, "Expected symbol for field type.");
751 }
752
753#define CONVERT(upb, ruby) \
754 if (SYM2ID(type) == rb_intern( # ruby )) { \
755 return UPB_TYPE_ ## upb; \
756 }
757
758 CONVERT(FLOAT, float);
759 CONVERT(DOUBLE, double);
760 CONVERT(BOOL, bool);
761 CONVERT(STRING, string);
762 CONVERT(BYTES, bytes);
763 CONVERT(MESSAGE, message);
764 CONVERT(ENUM, enum);
765 CONVERT(INT32, int32);
766 CONVERT(INT64, int64);
767 CONVERT(UINT32, uint32);
768 CONVERT(UINT64, uint64);
769
770#undef CONVERT
771
772 rb_raise(rb_eArgError, "Unknown field type.");
773 return 0;
774}
775
776static upb_descriptortype_t ruby_to_descriptortype(VALUE type) {
777 if (TYPE(type) != T_SYMBOL) {
778 rb_raise(rb_eArgError, "Expected symbol for field type.");
779 }
780
781#define CONVERT(upb, ruby) \
782 if (SYM2ID(type) == rb_intern( # ruby )) { \
783 return UPB_DESCRIPTOR_TYPE_ ## upb; \
784 }
785
786 CONVERT(FLOAT, float);
787 CONVERT(DOUBLE, double);
788 CONVERT(BOOL, bool);
789 CONVERT(STRING, string);
790 CONVERT(BYTES, bytes);
791 CONVERT(MESSAGE, message);
792 CONVERT(GROUP, group);
793 CONVERT(ENUM, enum);
794 CONVERT(INT32, int32);
795 CONVERT(INT64, int64);
796 CONVERT(UINT32, uint32);
797 CONVERT(UINT64, uint64);
798 CONVERT(SINT32, sint32);
799 CONVERT(SINT64, sint64);
800 CONVERT(FIXED32, fixed32);
801 CONVERT(FIXED64, fixed64);
802 CONVERT(SFIXED32, sfixed32);
803 CONVERT(SFIXED64, sfixed64);
804
805#undef CONVERT
806
807 rb_raise(rb_eArgError, "Unknown field type.");
808 return 0;
809}
810
811static VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
812 switch (type) {
813#define CONVERT(upb, ruby) \
814 case UPB_DESCRIPTOR_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
815 CONVERT(FLOAT, float);
816 CONVERT(DOUBLE, double);
817 CONVERT(BOOL, bool);
818 CONVERT(STRING, string);
819 CONVERT(BYTES, bytes);
820 CONVERT(MESSAGE, message);
821 CONVERT(GROUP, group);
822 CONVERT(ENUM, enum);
823 CONVERT(INT32, int32);
824 CONVERT(INT64, int64);
825 CONVERT(UINT32, uint32);
826 CONVERT(UINT64, uint64);
827 CONVERT(SINT32, sint32);
828 CONVERT(SINT64, sint64);
829 CONVERT(FIXED32, fixed32);
830 CONVERT(FIXED64, fixed64);
831 CONVERT(SFIXED32, sfixed32);
832 CONVERT(SFIXED64, sfixed64);
833#undef CONVERT
834 }
835 return Qnil;
836}
837
838/*
839 * call-seq:
840 * FieldDescriptor.type => type
841 *
842 * Returns this field's type, as a Ruby symbol, or nil if not yet set.
843 *
844 * Valid field types are:
845 * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
846 * :bytes, :message.
847 */
848static VALUE FieldDescriptor__type(VALUE _self) {
849 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
850 return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef));
851}
852
853/*
854 * call-seq:
855 * FieldDescriptor.default => default
856 *
857 * Returns this field's default, as a Ruby object, or nil if not yet set.
858 */
859static VALUE FieldDescriptor_default(VALUE _self) {
860 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
861 const upb_fielddef *f = self->fielddef;
862 upb_msgval default_val = {0};
863 if (upb_fielddef_issubmsg(f)) {
864 return Qnil;
865 } else if (!upb_fielddef_isseq(f)) {
866 default_val = upb_fielddef_default(f);
867 }
868 return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
869}
870
Lukas Fittl2c354c62021-03-01 00:15:58 -0800871
872/*
873 * call-seq:
874 * FieldDescriptor.json_name => json_name
875 *
876 * Returns this field's json_name, as a Ruby string, or nil if not yet set.
877 */
878static VALUE FieldDescriptor_json_name(VALUE _self) {
879 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
880 const upb_fielddef *f = self->fielddef;
881 const char *json_name = upb_fielddef_jsonname(f);
Lukas Fittl07f263c2021-04-03 18:42:43 -0700882 return rb_str_new2(json_name);
Lukas Fittl2c354c62021-03-01 00:15:58 -0800883}
884
Joshua Haberman9abf6e22021-01-13 12:16:25 -0800885/*
886 * call-seq:
887 * FieldDescriptor.label => label
888 *
889 * Returns this field's label (i.e., plurality), as a Ruby symbol.
890 *
891 * Valid field labels are:
892 * :optional, :repeated
893 */
894static VALUE FieldDescriptor_label(VALUE _self) {
895 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
896 switch (upb_fielddef_label(self->fielddef)) {
897#define CONVERT(upb, ruby) \
898 case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby ));
899
900 CONVERT(OPTIONAL, optional);
901 CONVERT(REQUIRED, required);
902 CONVERT(REPEATED, repeated);
903
904#undef CONVERT
905 }
906
907 return Qnil;
908}
909
910/*
911 * call-seq:
912 * FieldDescriptor.number => number
913 *
914 * Returns the tag number for this field.
915 */
916static VALUE FieldDescriptor_number(VALUE _self) {
917 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
918 return INT2NUM(upb_fielddef_number(self->fielddef));
919}
920
921/*
922 * call-seq:
923 * FieldDescriptor.submsg_name => submsg_name
924 *
925 * Returns the name of the message or enum type corresponding to this field, if
926 * it is a message or enum field (respectively), or nil otherwise. This type
927 * name will be resolved within the context of the pool to which the containing
928 * message type is added.
929 */
930static VALUE FieldDescriptor_submsg_name(VALUE _self) {
931 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
932 switch (upb_fielddef_type(self->fielddef)) {
933 case UPB_TYPE_ENUM:
934 return rb_str_new2(
935 upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef)));
936 case UPB_TYPE_MESSAGE:
937 return rb_str_new2(
938 upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef)));
939 default:
940 return Qnil;
941 }
942}
943
944/*
945 * call-seq:
946 * FieldDescriptor.subtype => message_or_enum_descriptor
947 *
948 * Returns the message or enum descriptor corresponding to this field's type if
949 * it is a message or enum field, respectively, or nil otherwise. Cannot be
950 * called *until* the containing message type is added to a pool (and thus
951 * resolved).
952 */
953static VALUE FieldDescriptor_subtype(VALUE _self) {
954 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
955 switch (upb_fielddef_type(self->fielddef)) {
956 case UPB_TYPE_ENUM:
957 return get_enumdef_obj(self->descriptor_pool,
958 upb_fielddef_enumsubdef(self->fielddef));
959 case UPB_TYPE_MESSAGE:
960 return get_msgdef_obj(self->descriptor_pool,
961 upb_fielddef_msgsubdef(self->fielddef));
962 default:
963 return Qnil;
964 }
965}
966
967/*
968 * call-seq:
969 * FieldDescriptor.get(message) => value
970 *
971 * Returns the value set for this field on the given message. Raises an
972 * exception if message is of the wrong type.
973 */
974static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
975 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
976 const upb_msgdef *m;
Joshua Haberman4e3ea742021-02-22 17:14:46 -0800977
978 Message_Get(msg_rb, &m);
Joshua Haberman9abf6e22021-01-13 12:16:25 -0800979
980 if (m != upb_fielddef_containingtype(self->fielddef)) {
981 rb_raise(cTypeError, "get method called on wrong message type");
982 }
983
Joshua Haberman4e3ea742021-02-22 17:14:46 -0800984 return Message_getfield(msg_rb, self->fielddef);
Joshua Haberman9abf6e22021-01-13 12:16:25 -0800985}
986
987/*
988 * call-seq:
989 * FieldDescriptor.has?(message) => boolean
990 *
991 * Returns whether the value is set on the given message. Raises an
992 * exception when calling for fields that do not have presence.
993 */
994static VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
995 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
996 const upb_msgdef *m;
997 const upb_msgdef *msg = Message_Get(msg_rb, &m);
998
999 if (m != upb_fielddef_containingtype(self->fielddef)) {
1000 rb_raise(cTypeError, "has method called on wrong message type");
1001 } else if (!upb_fielddef_haspresence(self->fielddef)) {
1002 rb_raise(rb_eArgError, "does not track presence");
1003 }
1004
1005 return upb_msg_has(msg, self->fielddef) ? Qtrue : Qfalse;
1006}
1007
1008/*
1009 * call-seq:
1010 * FieldDescriptor.clear(message)
1011 *
1012 * Clears the field from the message if it's set.
1013 */
1014static VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
1015 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
1016 const upb_msgdef *m;
1017 upb_msgdef *msg = Message_GetMutable(msg_rb, &m);
1018
1019 if (m != upb_fielddef_containingtype(self->fielddef)) {
1020 rb_raise(cTypeError, "has method called on wrong message type");
1021 }
1022
1023 upb_msg_clearfield(msg, self->fielddef);
1024 return Qnil;
1025}
1026
1027/*
1028 * call-seq:
1029 * FieldDescriptor.set(message, value)
1030 *
1031 * Sets the value corresponding to this field to the given value on the given
1032 * message. Raises an exception if message is of the wrong type. Performs the
1033 * ordinary type-checks for field setting.
1034 */
1035static VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
1036 FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
1037 const upb_msgdef *m;
1038 upb_msgdef *msg = Message_GetMutable(msg_rb, &m);
1039 upb_arena *arena = Arena_get(Message_GetArena(msg_rb));
1040 upb_msgval msgval;
1041
1042 if (m != upb_fielddef_containingtype(self->fielddef)) {
1043 rb_raise(cTypeError, "set method called on wrong message type");
1044 }
1045
1046 msgval = Convert_RubyToUpb(value, upb_fielddef_name(self->fielddef),
1047 TypeInfo_get(self->fielddef), arena);
1048 upb_msg_set(msg, self->fielddef, msgval, arena);
1049 return Qnil;
1050}
1051
1052static void FieldDescriptor_register(VALUE module) {
1053 VALUE klass = rb_define_class_under(
1054 module, "FieldDescriptor", rb_cObject);
1055 rb_define_alloc_func(klass, FieldDescriptor_alloc);
1056 rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3);
1057 rb_define_method(klass, "name", FieldDescriptor_name, 0);
1058 rb_define_method(klass, "type", FieldDescriptor__type, 0);
1059 rb_define_method(klass, "default", FieldDescriptor_default, 0);
Lukas Fittl2c354c62021-03-01 00:15:58 -08001060 rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0);
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001061 rb_define_method(klass, "label", FieldDescriptor_label, 0);
1062 rb_define_method(klass, "number", FieldDescriptor_number, 0);
1063 rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
1064 rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
1065 rb_define_method(klass, "has?", FieldDescriptor_has, 1);
1066 rb_define_method(klass, "clear", FieldDescriptor_clear, 1);
1067 rb_define_method(klass, "get", FieldDescriptor_get, 1);
1068 rb_define_method(klass, "set", FieldDescriptor_set, 2);
1069 rb_gc_register_address(&cFieldDescriptor);
1070 cFieldDescriptor = klass;
1071}
1072
1073// -----------------------------------------------------------------------------
1074// OneofDescriptor.
1075// -----------------------------------------------------------------------------
1076
1077typedef struct {
1078 const upb_oneofdef* oneofdef;
1079 VALUE descriptor_pool; // Owns the upb_oneofdef.
1080} OneofDescriptor;
1081
1082static VALUE cOneofDescriptor = Qnil;
1083
1084static void OneofDescriptor_mark(void* _self) {
1085 OneofDescriptor* self = _self;
1086 rb_gc_mark(self->descriptor_pool);
1087}
1088
1089static const rb_data_type_t OneofDescriptor_type = {
1090 "Google::Protobuf::OneofDescriptor",
1091 {OneofDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1092 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
1093};
1094
1095static OneofDescriptor* ruby_to_OneofDescriptor(VALUE val) {
1096 OneofDescriptor* ret;
1097 TypedData_Get_Struct(val, OneofDescriptor, &OneofDescriptor_type, ret);
1098 return ret;
1099}
1100
1101/*
1102 * call-seq:
1103 * OneofDescriptor.new => oneof_descriptor
1104 *
1105 * Creates a new, empty, oneof descriptor. The oneof may only be modified prior
1106 * to being added to a message descriptor which is subsequently added to a pool.
1107 */
1108static VALUE OneofDescriptor_alloc(VALUE klass) {
1109 OneofDescriptor* self = ALLOC(OneofDescriptor);
1110 VALUE ret = TypedData_Wrap_Struct(klass, &OneofDescriptor_type, self);
1111 self->oneofdef = NULL;
1112 self->descriptor_pool = Qnil;
1113 return ret;
1114}
1115
1116/*
1117 * call-seq:
1118 * OneofDescriptor.new(c_only_cookie, pool, ptr) => OneofDescriptor
1119 *
1120 * Creates a descriptor wrapper object. May only be called from C.
1121 */
1122static VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
1123 VALUE descriptor_pool, VALUE ptr) {
1124 OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1125
1126 if (cookie != c_only_cookie) {
1127 rb_raise(rb_eRuntimeError,
1128 "Descriptor objects may not be created from Ruby.");
1129 }
1130
1131 self->descriptor_pool = descriptor_pool;
1132 self->oneofdef = (const upb_oneofdef*)NUM2ULL(ptr);
1133
1134 return Qnil;
1135}
1136
1137/*
1138 * call-seq:
1139 * OneofDescriptor.name => name
1140 *
1141 * Returns the name of this oneof.
1142 */
1143static VALUE OneofDescriptor_name(VALUE _self) {
1144 OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1145 return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
1146}
1147
1148/*
1149 * call-seq:
1150 * OneofDescriptor.each(&block) => nil
1151 *
1152 * Iterates through fields in this oneof, yielding to the block on each one.
1153 */
1154static VALUE OneofDescriptor_each(VALUE _self) {
1155 OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
1156 upb_oneof_iter it;
1157 for (upb_oneof_begin(&it, self->oneofdef);
1158 !upb_oneof_done(&it);
1159 upb_oneof_next(&it)) {
1160 const upb_fielddef* f = upb_oneof_iter_field(&it);
1161 VALUE obj = get_fielddef_obj(self->descriptor_pool, f);
1162 rb_yield(obj);
1163 }
1164 return Qnil;
1165}
1166
1167static void OneofDescriptor_register(VALUE module) {
1168 VALUE klass = rb_define_class_under(
1169 module, "OneofDescriptor", rb_cObject);
1170 rb_define_alloc_func(klass, OneofDescriptor_alloc);
1171 rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3);
1172 rb_define_method(klass, "name", OneofDescriptor_name, 0);
1173 rb_define_method(klass, "each", OneofDescriptor_each, 0);
1174 rb_include_module(klass, rb_mEnumerable);
1175 rb_gc_register_address(&cOneofDescriptor);
1176 cOneofDescriptor = klass;
1177}
1178
1179// -----------------------------------------------------------------------------
1180// EnumDescriptor.
1181// -----------------------------------------------------------------------------
1182
1183typedef struct {
1184 const upb_enumdef* enumdef;
1185 VALUE module; // begins as nil
1186 VALUE descriptor_pool; // Owns the upb_enumdef.
1187} EnumDescriptor;
1188
1189static VALUE cEnumDescriptor = Qnil;
1190
1191static void EnumDescriptor_mark(void* _self) {
1192 EnumDescriptor* self = _self;
1193 rb_gc_mark(self->module);
1194 rb_gc_mark(self->descriptor_pool);
1195}
1196
1197static const rb_data_type_t EnumDescriptor_type = {
1198 "Google::Protobuf::EnumDescriptor",
1199 {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1200 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
1201};
1202
1203static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) {
1204 EnumDescriptor* ret;
1205 TypedData_Get_Struct(val, EnumDescriptor, &EnumDescriptor_type, ret);
1206 return ret;
1207}
1208
1209static VALUE EnumDescriptor_alloc(VALUE klass) {
1210 EnumDescriptor* self = ALLOC(EnumDescriptor);
1211 VALUE ret = TypedData_Wrap_Struct(klass, &EnumDescriptor_type, self);
1212 self->enumdef = NULL;
1213 self->module = Qnil;
1214 self->descriptor_pool = Qnil;
1215 return ret;
1216}
1217
1218// Exposed to other modules in defs.h.
1219const upb_enumdef *EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) {
1220 EnumDescriptor *desc = ruby_to_EnumDescriptor(enum_desc_rb);
1221 return desc->enumdef;
1222}
1223
1224/*
1225 * call-seq:
1226 * EnumDescriptor.new(c_only_cookie, ptr) => EnumDescriptor
1227 *
1228 * Creates a descriptor wrapper object. May only be called from C.
1229 */
1230static VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
1231 VALUE descriptor_pool, VALUE ptr) {
1232 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1233
1234 if (cookie != c_only_cookie) {
1235 rb_raise(rb_eRuntimeError,
1236 "Descriptor objects may not be created from Ruby.");
1237 }
1238
1239 self->descriptor_pool = descriptor_pool;
1240 self->enumdef = (const upb_enumdef*)NUM2ULL(ptr);
1241
1242 return Qnil;
1243}
1244
1245/*
1246 * call-seq:
1247 * EnumDescriptor.file_descriptor
1248 *
1249 * Returns the FileDescriptor object this enum belongs to.
1250 */
1251static VALUE EnumDescriptor_file_descriptor(VALUE _self) {
1252 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1253 return get_filedef_obj(self->descriptor_pool,
1254 upb_enumdef_file(self->enumdef));
1255}
1256
1257/*
1258 * call-seq:
1259 * EnumDescriptor.name => name
1260 *
1261 * Returns the name of this enum type.
1262 */
1263static VALUE EnumDescriptor_name(VALUE _self) {
1264 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1265 return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef));
1266}
1267
1268/*
1269 * call-seq:
1270 * EnumDescriptor.lookup_name(name) => value
1271 *
1272 * Returns the numeric value corresponding to the given key name (as a Ruby
1273 * symbol), or nil if none.
1274 */
1275static VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
1276 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1277 const char* name_str= rb_id2name(SYM2ID(name));
1278 int32_t val = 0;
1279 if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) {
1280 return INT2NUM(val);
1281 } else {
1282 return Qnil;
1283 }
1284}
1285
1286/*
1287 * call-seq:
1288 * EnumDescriptor.lookup_value(name) => value
1289 *
1290 * Returns the key name (as a Ruby symbol) corresponding to the integer value,
1291 * or nil if none.
1292 */
1293static VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
1294 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1295 int32_t val = NUM2INT(number);
1296 const char* name = upb_enumdef_iton(self->enumdef, val);
1297 if (name != NULL) {
1298 return ID2SYM(rb_intern(name));
1299 } else {
1300 return Qnil;
1301 }
1302}
1303
1304/*
1305 * call-seq:
1306 * EnumDescriptor.each(&block)
1307 *
1308 * Iterates over key => value mappings in this enum's definition, yielding to
1309 * the block with (key, value) arguments for each one.
1310 */
1311static VALUE EnumDescriptor_each(VALUE _self) {
1312 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1313
1314 upb_enum_iter it;
1315 for (upb_enum_begin(&it, self->enumdef);
1316 !upb_enum_done(&it);
1317 upb_enum_next(&it)) {
1318 VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it)));
1319 VALUE number = INT2NUM(upb_enum_iter_number(&it));
1320 rb_yield_values(2, key, number);
1321 }
1322
1323 return Qnil;
1324}
1325
1326/*
1327 * call-seq:
1328 * EnumDescriptor.enummodule => module
1329 *
1330 * Returns the Ruby module corresponding to this enum type.
1331 */
1332static VALUE EnumDescriptor_enummodule(VALUE _self) {
1333 EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
1334 if (self->module == Qnil) {
1335 self->module = build_module_from_enumdesc(_self);
1336 }
1337 return self->module;
1338}
1339
1340static void EnumDescriptor_register(VALUE module) {
1341 VALUE klass = rb_define_class_under(
1342 module, "EnumDescriptor", rb_cObject);
1343 rb_define_alloc_func(klass, EnumDescriptor_alloc);
1344 rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3);
1345 rb_define_method(klass, "name", EnumDescriptor_name, 0);
1346 rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
1347 rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
1348 rb_define_method(klass, "each", EnumDescriptor_each, 0);
1349 rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
1350 rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0);
1351 rb_include_module(klass, rb_mEnumerable);
1352 rb_gc_register_address(&cEnumDescriptor);
1353 cEnumDescriptor = klass;
1354}
1355
1356// -----------------------------------------------------------------------------
1357// FileBuilderContext.
1358// -----------------------------------------------------------------------------
1359
1360typedef struct {
1361 upb_arena *arena;
1362 google_protobuf_FileDescriptorProto* file_proto;
1363 VALUE descriptor_pool;
1364} FileBuilderContext;
1365
1366static VALUE cFileBuilderContext = Qnil;
1367
1368static void FileBuilderContext_mark(void* _self) {
1369 FileBuilderContext* self = _self;
1370 rb_gc_mark(self->descriptor_pool);
1371}
1372
1373static void FileBuilderContext_free(void* _self) {
1374 FileBuilderContext* self = _self;
1375 upb_arena_free(self->arena);
1376 xfree(self);
1377}
1378
1379static const rb_data_type_t FileBuilderContext_type = {
1380 "Google::Protobuf::Internal::FileBuilderContext",
1381 {FileBuilderContext_mark, FileBuilderContext_free, NULL},
1382 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
1383};
1384
1385static FileBuilderContext* ruby_to_FileBuilderContext(VALUE val) {
1386 FileBuilderContext* ret;
1387 TypedData_Get_Struct(val, FileBuilderContext, &FileBuilderContext_type, ret);
1388 return ret;
1389}
1390
1391static upb_strview FileBuilderContext_strdup2(VALUE _self, const char *str) {
1392 FileBuilderContext* self = ruby_to_FileBuilderContext(_self);
1393 upb_strview ret;
1394 char *data;
1395
1396 ret.size = strlen(str);
1397 data = upb_malloc(upb_arena_alloc(self->arena), ret.size + 1);
1398 ret.data = data;
1399 memcpy(data, str, ret.size);
1400 /* Null-terminate required by rewrite_enum_defaults() above. */
1401 data[ret.size] = '\0';
1402 return ret;
1403}
1404
1405static upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str) {
1406 return FileBuilderContext_strdup2(_self, get_str(rb_str));
1407}
1408
1409static upb_strview FileBuilderContext_strdup_sym(VALUE _self, VALUE rb_sym) {
1410 Check_Type(rb_sym, T_SYMBOL);
1411 return FileBuilderContext_strdup(_self, rb_id2str(SYM2ID(rb_sym)));
1412}
1413
1414static VALUE FileBuilderContext_alloc(VALUE klass) {
1415 FileBuilderContext* self = ALLOC(FileBuilderContext);
1416 VALUE ret = TypedData_Wrap_Struct(klass, &FileBuilderContext_type, self);
1417 self->arena = upb_arena_new();
1418 self->file_proto = google_protobuf_FileDescriptorProto_new(self->arena);
1419 self->descriptor_pool = Qnil;
1420 return ret;
1421}
1422
1423/*
1424 * call-seq:
1425 * FileBuilderContext.new(descriptor_pool) => context
1426 *
1427 * Create a new file builder context for the given file descriptor and
1428 * builder context. This class is intended to serve as a DSL context to be used
1429 * with #instance_eval.
1430 */
1431static VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
1432 VALUE name, VALUE options) {
1433 FileBuilderContext* self = ruby_to_FileBuilderContext(_self);
1434 self->descriptor_pool = descriptor_pool;
1435
1436 google_protobuf_FileDescriptorProto_set_name(
1437 self->file_proto, FileBuilderContext_strdup(_self, name));
1438
1439 // Default syntax for Ruby is proto3.
1440 google_protobuf_FileDescriptorProto_set_syntax(
1441 self->file_proto,
1442 FileBuilderContext_strdup(_self, rb_str_new2("proto3")));
1443
1444 if (options != Qnil) {
1445 VALUE syntax;
1446
1447 Check_Type(options, T_HASH);
1448 syntax = rb_hash_lookup2(options, ID2SYM(rb_intern("syntax")), Qnil);
1449
1450 if (syntax != Qnil) {
1451 VALUE syntax_str;
1452
1453 Check_Type(syntax, T_SYMBOL);
1454 syntax_str = rb_id2str(SYM2ID(syntax));
1455 google_protobuf_FileDescriptorProto_set_syntax(
1456 self->file_proto, FileBuilderContext_strdup(_self, syntax_str));
1457 }
1458 }
1459
1460 return Qnil;
1461}
1462
1463static void MessageBuilderContext_add_synthetic_oneofs(VALUE _self);
1464
1465/*
1466 * call-seq:
1467 * FileBuilderContext.add_message(name, &block)
1468 *
1469 * Creates a new, empty descriptor with the given name, and invokes the block in
1470 * the context of a MessageBuilderContext on that descriptor. The block can then
1471 * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
1472 * methods to define the message fields.
1473 *
1474 * This is the recommended, idiomatic way to build message definitions.
1475 */
1476static VALUE FileBuilderContext_add_message(VALUE _self, VALUE name) {
1477 VALUE args[2] = { _self, name };
1478 VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
1479 VALUE block = rb_block_proc();
1480 rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
1481 MessageBuilderContext_add_synthetic_oneofs(ctx);
1482 return Qnil;
1483}
1484
Joshua Haberman63f324a2019-08-14 22:41:37 +01001485/* We have to do some relatively complicated logic here for backward
1486 * compatibility.
1487 *
1488 * In descriptor.proto, messages are nested inside other messages if that is
1489 * what the original .proto file looks like. For example, suppose we have this
1490 * foo.proto:
1491 *
1492 * package foo;
1493 * message Bar {
1494 * message Baz {}
1495 * }
1496 *
1497 * The descriptor for this must look like this:
1498 *
1499 * file {
1500 * name: "test.proto"
1501 * package: "foo"
1502 * message_type {
1503 * name: "Bar"
1504 * nested_type {
1505 * name: "Baz"
1506 * }
1507 * }
1508 * }
1509 *
1510 * However, the Ruby generated code has always generated messages in a flat,
1511 * non-nested way:
1512 *
1513 * Google::Protobuf::DescriptorPool.generated_pool.build do
1514 * add_message "foo.Bar" do
1515 * end
1516 * add_message "foo.Bar.Baz" do
1517 * end
1518 * end
1519 *
1520 * Here we need to do a translation where we turn this generated code into the
1521 * above descriptor. We need to infer that "foo" is the package name, and not
1522 * a message itself.
1523 *
1524 * We delegate to Ruby to compute the transformation, for more concice and
1525 * readable code than we can do in C */
1526static void rewrite_names(VALUE _file_builder,
1527 google_protobuf_FileDescriptorProto* file_proto) {
1528 FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
1529 upb_arena *arena = file_builder->arena;
1530 // Build params (package, msg_names, enum_names).
1531 VALUE package = Qnil;
1532 VALUE msg_names = rb_ary_new();
1533 VALUE enum_names = rb_ary_new();
1534 size_t msg_count, enum_count, i;
1535 VALUE new_package, nesting, msg_ents, enum_ents;
1536 google_protobuf_DescriptorProto** msgs;
1537 google_protobuf_EnumDescriptorProto** enums;
1538
1539 if (google_protobuf_FileDescriptorProto_has_package(file_proto)) {
1540 upb_strview package_str =
1541 google_protobuf_FileDescriptorProto_package(file_proto);
1542 package = rb_str_new(package_str.data, package_str.size);
1543 }
1544
1545 msgs = google_protobuf_FileDescriptorProto_mutable_message_type(file_proto,
1546 &msg_count);
1547 for (i = 0; i < msg_count; i++) {
1548 upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
1549 rb_ary_push(msg_names, rb_str_new(name.data, name.size));
1550 }
1551
1552 enums = google_protobuf_FileDescriptorProto_mutable_enum_type(file_proto,
1553 &enum_count);
1554 for (i = 0; i < enum_count; i++) {
1555 upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
1556 rb_ary_push(enum_names, rb_str_new(name.data, name.size));
1557 }
1558
1559 {
1560 // Call Ruby code to calculate package name and nesting.
1561 VALUE args[3] = { package, msg_names, enum_names };
1562 VALUE internal = rb_eval_string("Google::Protobuf::Internal");
1563 VALUE ret = rb_funcallv(internal, rb_intern("fixup_descriptor"), 3, args);
1564
1565 new_package = rb_ary_entry(ret, 0);
1566 nesting = rb_ary_entry(ret, 1);
1567 }
1568
1569 // Rewrite package and names.
1570 if (new_package != Qnil) {
1571 upb_strview new_package_str =
1572 FileBuilderContext_strdup(_file_builder, new_package);
1573 google_protobuf_FileDescriptorProto_set_package(file_proto,
1574 new_package_str);
1575 }
1576
1577 for (i = 0; i < msg_count; i++) {
1578 upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
1579 remove_path(&name);
1580 google_protobuf_DescriptorProto_set_name(msgs[i], name);
1581 }
1582
1583 for (i = 0; i < enum_count; i++) {
1584 upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
1585 remove_path(&name);
1586 google_protobuf_EnumDescriptorProto_set_name(enums[i], name);
1587 }
1588
1589 // Rewrite nesting.
1590 msg_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("msgs")));
1591 enum_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("enums")));
1592
1593 Check_Type(msg_ents, T_ARRAY);
1594 Check_Type(enum_ents, T_ARRAY);
1595
1596 for (i = 0; i < (size_t)RARRAY_LEN(msg_ents); i++) {
1597 VALUE msg_ent = rb_ary_entry(msg_ents, i);
1598 VALUE pos = rb_hash_aref(msg_ent, ID2SYM(rb_intern("pos")));
1599 msgs[i] = msgs[NUM2INT(pos)];
1600 rewrite_nesting(msg_ent, msgs[i], msgs, enums, arena);
1601 }
1602
1603 for (i = 0; i < (size_t)RARRAY_LEN(enum_ents); i++) {
1604 VALUE enum_pos = rb_ary_entry(enum_ents, i);
1605 enums[i] = enums[NUM2INT(enum_pos)];
1606 }
1607
1608 google_protobuf_FileDescriptorProto_resize_message_type(
1609 file_proto, RARRAY_LEN(msg_ents), arena);
1610 google_protobuf_FileDescriptorProto_resize_enum_type(
1611 file_proto, RARRAY_LEN(enum_ents), arena);
Chris Fallin973f4252014-11-18 14:19:58 -08001612}
1613
Chris Fallin973f4252014-11-18 14:19:58 -08001614/*
1615 * call-seq:
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001616 * FileBuilderContext.add_enum(name, &block)
Chris Fallin973f4252014-11-18 14:19:58 -08001617 *
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001618 * Creates a new, empty enum descriptor with the given name, and invokes the
1619 * block in the context of an EnumBuilderContext on that descriptor. The block
1620 * can then call EnumBuilderContext#add_value to define the enum values.
Chris Fallin973f4252014-11-18 14:19:58 -08001621 *
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001622 * This is the recommended, idiomatic way to build enum definitions.
Chris Fallin973f4252014-11-18 14:19:58 -08001623 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001624static VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name) {
1625 VALUE args[2] = { _self, name };
1626 VALUE ctx = rb_class_new_instance(2, args, cEnumBuilderContext);
Chris Fallin973f4252014-11-18 14:19:58 -08001627 VALUE block = rb_block_proc();
1628 rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
Chris Fallin973f4252014-11-18 14:19:58 -08001629 return Qnil;
1630}
1631
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001632static void FileBuilderContext_build(VALUE _self) {
1633 FileBuilderContext* self = ruby_to_FileBuilderContext(_self);
1634 DescriptorPool* pool = ruby_to_DescriptorPool(self->descriptor_pool);
1635 upb_status status;
Joshua Haberman63f324a2019-08-14 22:41:37 +01001636
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001637 rewrite_enum_defaults(pool->symtab, self->file_proto);
1638 rewrite_names(_self, self->file_proto);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001639
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001640 upb_status_clear(&status);
1641 if (!upb_symtab_addfile(pool->symtab, self->file_proto, &status)) {
1642 rb_raise(cTypeError, "Unable to add defs to DescriptorPool: %s",
1643 upb_status_errmsg(&status));
Joshua Haberman1c9fb9d2019-08-16 06:42:13 -07001644 }
Chris Fallin973f4252014-11-18 14:19:58 -08001645}
1646
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001647static void FileBuilderContext_register(VALUE module) {
1648 VALUE klass = rb_define_class_under(module, "FileBuilderContext", rb_cObject);
1649 rb_define_alloc_func(klass, FileBuilderContext_alloc);
1650 rb_define_method(klass, "initialize", FileBuilderContext_initialize, 3);
1651 rb_define_method(klass, "add_message", FileBuilderContext_add_message, 1);
1652 rb_define_method(klass, "add_enum", FileBuilderContext_add_enum, 1);
1653 rb_gc_register_address(&cFileBuilderContext);
1654 cFileBuilderContext = klass;
Chris Fallin973f4252014-11-18 14:19:58 -08001655}
1656
1657// -----------------------------------------------------------------------------
1658// MessageBuilderContext.
1659// -----------------------------------------------------------------------------
1660
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001661typedef struct {
1662 google_protobuf_DescriptorProto* msg_proto;
1663 VALUE file_builder;
1664} MessageBuilderContext;
Chris Fallin973f4252014-11-18 14:19:58 -08001665
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001666static VALUE cMessageBuilderContext = Qnil;
1667
1668static void MessageBuilderContext_mark(void* _self) {
Chris Fallin973f4252014-11-18 14:19:58 -08001669 MessageBuilderContext* self = _self;
Joshua Haberman63f324a2019-08-14 22:41:37 +01001670 rb_gc_mark(self->file_builder);
Chris Fallin973f4252014-11-18 14:19:58 -08001671}
1672
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001673static const rb_data_type_t MessageBuilderContext_type = {
1674 "Google::Protobuf::Internal::MessageBuilderContext",
1675 {MessageBuilderContext_mark, RUBY_DEFAULT_FREE, NULL},
1676 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
1677};
Chris Fallin973f4252014-11-18 14:19:58 -08001678
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001679static MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE val) {
1680 MessageBuilderContext* ret;
1681 TypedData_Get_Struct(val, MessageBuilderContext, &MessageBuilderContext_type,
1682 ret);
Chris Fallin973f4252014-11-18 14:19:58 -08001683 return ret;
1684}
1685
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001686static VALUE MessageBuilderContext_alloc(VALUE klass) {
1687 MessageBuilderContext* self = ALLOC(MessageBuilderContext);
1688 VALUE ret = TypedData_Wrap_Struct(klass, &MessageBuilderContext_type, self);
1689 self->file_builder = Qnil;
1690 return ret;
Chris Fallin973f4252014-11-18 14:19:58 -08001691}
1692
1693/*
1694 * call-seq:
Joshua Haberman63f324a2019-08-14 22:41:37 +01001695 * MessageBuilderContext.new(file_builder, name) => context
Chris Fallin973f4252014-11-18 14:19:58 -08001696 *
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001697 * Create a new message builder context around the given message descriptor and
1698 * builder context. This class is intended to serve as a DSL context to be used
1699 * with #instance_eval.
Chris Fallin973f4252014-11-18 14:19:58 -08001700 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001701static VALUE MessageBuilderContext_initialize(VALUE _self, VALUE _file_builder,
1702 VALUE name) {
1703 MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001704 FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
1705 google_protobuf_FileDescriptorProto* file_proto = file_builder->file_proto;
1706
1707 self->file_builder = _file_builder;
1708 self->msg_proto = google_protobuf_FileDescriptorProto_add_message_type(
1709 file_proto, file_builder->arena);
1710
1711 google_protobuf_DescriptorProto_set_name(
1712 self->msg_proto, FileBuilderContext_strdup(_file_builder, name));
1713
Chris Fallin973f4252014-11-18 14:19:58 -08001714 return Qnil;
1715}
1716
Joshua Haberman63f324a2019-08-14 22:41:37 +01001717static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
1718 VALUE type, VALUE number, VALUE type_class,
Joshua Haberman6b759682020-04-23 12:54:25 -07001719 VALUE options, int oneof_index,
1720 bool proto3_optional) {
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001721 MessageBuilderContext* self = ruby_to_MessageBuilderContext(msgbuilder_rb);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001722 FileBuilderContext* file_context =
1723 ruby_to_FileBuilderContext(self->file_builder);
1724 google_protobuf_FieldDescriptorProto* field_proto;
1725 VALUE name_str;
Chris Fallin973f4252014-11-18 14:19:58 -08001726
Joshua Haberman63f324a2019-08-14 22:41:37 +01001727 field_proto = google_protobuf_DescriptorProto_add_field(self->msg_proto,
1728 file_context->arena);
1729
1730 Check_Type(name, T_SYMBOL);
1731 name_str = rb_id2str(SYM2ID(name));
1732
1733 google_protobuf_FieldDescriptorProto_set_name(
1734 field_proto, FileBuilderContext_strdup(self->file_builder, name_str));
1735 google_protobuf_FieldDescriptorProto_set_number(field_proto, NUM2INT(number));
1736 google_protobuf_FieldDescriptorProto_set_label(field_proto, (int)label);
1737 google_protobuf_FieldDescriptorProto_set_type(
1738 field_proto, (int)ruby_to_descriptortype(type));
Chris Fallin973f4252014-11-18 14:19:58 -08001739
Joshua Haberman6b759682020-04-23 12:54:25 -07001740 if (proto3_optional) {
1741 google_protobuf_FieldDescriptorProto_set_proto3_optional(field_proto, true);
1742 }
1743
Chris Fallin973f4252014-11-18 14:19:58 -08001744 if (type_class != Qnil) {
Harshit Choprad0535cc2017-08-25 12:11:15 -07001745 Check_Type(type_class, T_STRING);
1746
Chris Fallin973f4252014-11-18 14:19:58 -08001747 // Make it an absolute type name by prepending a dot.
1748 type_class = rb_str_append(rb_str_new2("."), type_class);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001749 google_protobuf_FieldDescriptorProto_set_type_name(
1750 field_proto, FileBuilderContext_strdup(self->file_builder, type_class));
Chris Fallin973f4252014-11-18 14:19:58 -08001751 }
1752
Harshit Choprad0535cc2017-08-25 12:11:15 -07001753 if (options != Qnil) {
1754 Check_Type(options, T_HASH);
1755
1756 if (rb_funcall(options, rb_intern("key?"), 1,
Joshua Haberman63f324a2019-08-14 22:41:37 +01001757 ID2SYM(rb_intern("default"))) == Qtrue) {
1758 VALUE default_value =
1759 rb_hash_lookup(options, ID2SYM(rb_intern("default")));
Harshit Choprad0535cc2017-08-25 12:11:15 -07001760
Joshua Haberman63f324a2019-08-14 22:41:37 +01001761 /* Call #to_s since all defaults are strings in the descriptor. */
1762 default_value = rb_funcall(default_value, rb_intern("to_s"), 0);
Harshit Choprad0535cc2017-08-25 12:11:15 -07001763
Joshua Haberman63f324a2019-08-14 22:41:37 +01001764 google_protobuf_FieldDescriptorProto_set_default_value(
1765 field_proto,
1766 FileBuilderContext_strdup(self->file_builder, default_value));
Harshit Choprad0535cc2017-08-25 12:11:15 -07001767 }
Lukas Fittl2c354c62021-03-01 00:15:58 -08001768
1769 if (rb_funcall(options, rb_intern("key?"), 1,
1770 ID2SYM(rb_intern("json_name"))) == Qtrue) {
1771 VALUE json_name =
1772 rb_hash_lookup(options, ID2SYM(rb_intern("json_name")));
1773
Lukas Fittl2c354c62021-03-01 00:15:58 -08001774 google_protobuf_FieldDescriptorProto_set_json_name(
1775 field_proto,
1776 FileBuilderContext_strdup(self->file_builder, json_name));
1777 }
Harshit Choprad0535cc2017-08-25 12:11:15 -07001778 }
1779
Joshua Haberman63f324a2019-08-14 22:41:37 +01001780 if (oneof_index >= 0) {
1781 google_protobuf_FieldDescriptorProto_set_oneof_index(field_proto,
1782 oneof_index);
1783 }
1784}
1785
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001786#if RUBY_API_VERSION_CODE >= 20700
1787static VALUE make_mapentry(VALUE _message_builder, VALUE types, int argc,
1788 const VALUE* argv, VALUE blockarg) {
1789 (void)blockarg;
1790#else
Joshua Haberman63f324a2019-08-14 22:41:37 +01001791static VALUE make_mapentry(VALUE _message_builder, VALUE types, int argc,
1792 VALUE* argv) {
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001793#endif
1794 MessageBuilderContext* message_builder =
1795 ruby_to_MessageBuilderContext(_message_builder);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001796 VALUE type_class = rb_ary_entry(types, 2);
1797 FileBuilderContext* file_context =
1798 ruby_to_FileBuilderContext(message_builder->file_builder);
1799 google_protobuf_MessageOptions* options =
1800 google_protobuf_DescriptorProto_mutable_options(
1801 message_builder->msg_proto, file_context->arena);
1802
1803 google_protobuf_MessageOptions_set_map_entry(options, true);
1804
1805 // optional <type> key = 1;
1806 rb_funcall(_message_builder, rb_intern("optional"), 3,
1807 ID2SYM(rb_intern("key")), rb_ary_entry(types, 0), INT2NUM(1));
1808
1809 // optional <type> value = 2;
1810 if (type_class == Qnil) {
1811 rb_funcall(_message_builder, rb_intern("optional"), 3,
1812 ID2SYM(rb_intern("value")), rb_ary_entry(types, 1), INT2NUM(2));
1813 } else {
1814 rb_funcall(_message_builder, rb_intern("optional"), 4,
1815 ID2SYM(rb_intern("value")), rb_ary_entry(types, 1), INT2NUM(2),
1816 type_class);
1817 }
1818
1819 return Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001820}
1821
1822/*
1823 * call-seq:
Harshit Choprad0535cc2017-08-25 12:11:15 -07001824 * MessageBuilderContext.optional(name, type, number, type_class = nil,
1825 * options = nil)
Chris Fallin973f4252014-11-18 14:19:58 -08001826 *
1827 * Defines a new optional field on this message type with the given type, tag
1828 * number, and type class (for message and enum fields). The type must be a Ruby
1829 * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
1830 * string, if present (as accepted by FieldDescriptor#submsg_name=).
1831 */
1832VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
Harshit Choprad0535cc2017-08-25 12:11:15 -07001833 VALUE name, type, number;
1834 VALUE type_class, options = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001835
Harshit Choprad0535cc2017-08-25 12:11:15 -07001836 rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1837
1838 // Allow passing (name, type, number, options) or
1839 // (name, type, number, type_class, options)
1840 if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1841 options = type_class;
1842 type_class = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001843 }
Chris Fallin973f4252014-11-18 14:19:58 -08001844
Joshua Haberman63f324a2019-08-14 22:41:37 +01001845 msgdef_add_field(_self, UPB_LABEL_OPTIONAL, name, type, number, type_class,
Joshua Haberman6b759682020-04-23 12:54:25 -07001846 options, -1, false);
1847
1848 return Qnil;
1849}
1850
1851/*
1852 * call-seq:
1853 * MessageBuilderContext.proto3_optional(name, type, number,
1854 * type_class = nil, options = nil)
1855 *
1856 * Defines a true proto3 optional field (that tracks presence) on this message
1857 * type with the given type, tag number, and type class (for message and enum
1858 * fields). The type must be a Ruby symbol (as accepted by
1859 * FieldDescriptor#type=) and the type_class must be a string, if present (as
1860 * accepted by FieldDescriptor#submsg_name=).
1861 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001862static VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv,
1863 VALUE _self) {
Joshua Haberman6b759682020-04-23 12:54:25 -07001864 VALUE name, type, number;
1865 VALUE type_class, options = Qnil;
1866
1867 rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1868
1869 // Allow passing (name, type, number, options) or
1870 // (name, type, number, type_class, options)
1871 if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1872 options = type_class;
1873 type_class = Qnil;
1874 }
1875
1876 msgdef_add_field(_self, UPB_LABEL_OPTIONAL, name, type, number, type_class,
1877 options, -1, true);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001878
1879 return Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001880}
1881
1882/*
1883 * call-seq:
Harshit Choprad0535cc2017-08-25 12:11:15 -07001884 * MessageBuilderContext.required(name, type, number, type_class = nil,
1885 * options = nil)
Chris Fallin973f4252014-11-18 14:19:58 -08001886 *
1887 * Defines a new required field on this message type with the given type, tag
1888 * number, and type class (for message and enum fields). The type must be a Ruby
1889 * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
1890 * string, if present (as accepted by FieldDescriptor#submsg_name=).
1891 *
1892 * Proto3 does not have required fields, but this method exists for
1893 * completeness. Any attempt to add a message type with required fields to a
1894 * pool will currently result in an error.
1895 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001896static VALUE MessageBuilderContext_required(int argc, VALUE* argv,
1897 VALUE _self) {
Harshit Choprad0535cc2017-08-25 12:11:15 -07001898 VALUE name, type, number;
1899 VALUE type_class, options = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001900
Harshit Choprad0535cc2017-08-25 12:11:15 -07001901 rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1902
1903 // Allow passing (name, type, number, options) or
1904 // (name, type, number, type_class, options)
1905 if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1906 options = type_class;
1907 type_class = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001908 }
Chris Fallin973f4252014-11-18 14:19:58 -08001909
Joshua Haberman63f324a2019-08-14 22:41:37 +01001910 msgdef_add_field(_self, UPB_LABEL_REQUIRED, name, type, number, type_class,
Joshua Haberman6b759682020-04-23 12:54:25 -07001911 options, -1, false);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001912
1913 return Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001914}
1915
1916/*
1917 * call-seq:
1918 * MessageBuilderContext.repeated(name, type, number, type_class = nil)
1919 *
1920 * Defines a new repeated field on this message type with the given type, tag
1921 * number, and type class (for message and enum fields). The type must be a Ruby
1922 * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
1923 * string, if present (as accepted by FieldDescriptor#submsg_name=).
1924 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001925static VALUE MessageBuilderContext_repeated(int argc, VALUE* argv,
1926 VALUE _self) {
Lukas Fittl2c354c62021-03-01 00:15:58 -08001927 VALUE name, type, number;
1928 VALUE type_class, options = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001929
Lukas Fittl2c354c62021-03-01 00:15:58 -08001930 rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1931
1932 // Allow passing (name, type, number, options) or
1933 // (name, type, number, type_class, options)
1934 if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1935 options = type_class;
1936 type_class = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001937 }
Chris Fallin973f4252014-11-18 14:19:58 -08001938
Joshua Haberman63f324a2019-08-14 22:41:37 +01001939 msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
Lukas Fittl2c354c62021-03-01 00:15:58 -08001940 options, -1, false);
Joshua Haberman63f324a2019-08-14 22:41:37 +01001941
1942 return Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08001943}
1944
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001945/*
1946 * call-seq:
1947 * MessageBuilderContext.map(name, key_type, value_type, number,
1948 * value_type_class = nil)
1949 *
Chris Fallin80276ac2015-01-06 18:01:32 -08001950 * Defines a new map field on this message type with the given key and value
1951 * types, tag number, and type class (for message and enum value types). The key
1952 * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
1953 * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
1954 * type_class must be a string, if present (as accepted by
1955 * FieldDescriptor#submsg_name=).
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001956 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08001957static VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
1958 MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
Josh Habermana1daeab2015-07-10 11:56:06 -07001959 VALUE name, key_type, value_type, number, type_class;
Joshua Haberman63f324a2019-08-14 22:41:37 +01001960 VALUE mapentry_desc_name;
1961 FileBuilderContext* file_builder;
1962 upb_strview msg_name;
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001963
1964 if (argc < 4) {
1965 rb_raise(rb_eArgError, "Expected at least 4 arguments.");
1966 }
Josh Habermana1daeab2015-07-10 11:56:06 -07001967 name = argv[0];
1968 key_type = argv[1];
1969 value_type = argv[2];
1970 number = argv[3];
1971 type_class = (argc > 4) ? argv[4] : Qnil;
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001972
1973 // Validate the key type. We can't accept enums, messages, or floats/doubles
1974 // as map keys. (We exclude these explicitly, and the field-descriptor setter
1975 // below then ensures that the type is one of the remaining valid options.)
1976 if (SYM2ID(key_type) == rb_intern("float") ||
1977 SYM2ID(key_type) == rb_intern("double") ||
1978 SYM2ID(key_type) == rb_intern("enum") ||
1979 SYM2ID(key_type) == rb_intern("message")) {
1980 rb_raise(rb_eArgError,
1981 "Cannot add a map field with a float, double, enum, or message "
1982 "type.");
1983 }
1984
Joshua Haberman63f324a2019-08-14 22:41:37 +01001985 file_builder = ruby_to_FileBuilderContext(self->file_builder);
1986
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001987 // Create a new message descriptor for the map entry message, and create a
1988 // repeated submessage field here with that type.
Joshua Haberman63f324a2019-08-14 22:41:37 +01001989 msg_name = google_protobuf_DescriptorProto_name(self->msg_proto);
1990 mapentry_desc_name = rb_str_new(msg_name.data, msg_name.size);
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001991 mapentry_desc_name = rb_str_cat2(mapentry_desc_name, "_MapEntry_");
Joshua Haberman63f324a2019-08-14 22:41:37 +01001992 mapentry_desc_name =
1993 rb_str_cat2(mapentry_desc_name, rb_id2name(SYM2ID(name)));
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08001994
Joshua Haberman1568dea2019-03-06 15:44:38 -08001995 {
Joshua Haberman63f324a2019-08-14 22:41:37 +01001996 // message <msgname>_MapEntry_ { /* ... */ }
1997 VALUE args[1] = {mapentry_desc_name};
1998 VALUE types = rb_ary_new3(3, key_type, value_type, type_class);
1999 rb_block_call(self->file_builder, rb_intern("add_message"), 1, args,
2000 make_mapentry, types);
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08002001 }
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08002002
Joshua Haberman63f324a2019-08-14 22:41:37 +01002003 // If this file is in a package, we need to qualify the map entry type.
2004 if (google_protobuf_FileDescriptorProto_has_package(file_builder->file_proto)) {
2005 upb_strview package_view =
2006 google_protobuf_FileDescriptorProto_package(file_builder->file_proto);
2007 VALUE package = rb_str_new(package_view.data, package_view.size);
2008 package = rb_str_cat2(package, ".");
2009 mapentry_desc_name = rb_str_concat(package, mapentry_desc_name);
Joshua Haberman1568dea2019-03-06 15:44:38 -08002010 }
2011
Joshua Haberman63f324a2019-08-14 22:41:37 +01002012 // repeated MapEntry <name> = <number>;
2013 rb_funcall(_self, rb_intern("repeated"), 4, name,
2014 ID2SYM(rb_intern("message")), number, mapentry_desc_name);
Chris Fallinfd1a3ff2015-01-06 15:44:09 -08002015
2016 return Qnil;
2017}
2018
Chris Fallinfcd88892015-01-13 18:14:39 -08002019/*
2020 * call-seq:
2021 * MessageBuilderContext.oneof(name, &block) => nil
2022 *
2023 * Creates a new OneofDescriptor with the given name, creates a
2024 * OneofBuilderContext attached to that OneofDescriptor, evaluates the given
2025 * block in the context of that OneofBuilderContext with #instance_eval, and
2026 * then adds the oneof to the message.
2027 *
2028 * This is the recommended, idiomatic way to build oneof definitions.
2029 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002030static VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
2031 MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002032 size_t oneof_count;
2033 FileBuilderContext* file_context =
2034 ruby_to_FileBuilderContext(self->file_builder);
2035 google_protobuf_OneofDescriptorProto* oneof_proto;
2036
2037 // Existing oneof_count becomes oneof_index.
2038 google_protobuf_DescriptorProto_oneof_decl(self->msg_proto, &oneof_count);
2039
2040 // Create oneof_proto and set its name.
2041 oneof_proto = google_protobuf_DescriptorProto_add_oneof_decl(
2042 self->msg_proto, file_context->arena);
2043 google_protobuf_OneofDescriptorProto_set_name(
2044 oneof_proto, FileBuilderContext_strdup_sym(self->file_builder, name));
2045
2046 // Evaluate the block with the builder as argument.
2047 {
2048 VALUE args[2] = { INT2NUM(oneof_count), _self };
2049 VALUE ctx = rb_class_new_instance(2, args, cOneofBuilderContext);
2050 VALUE block = rb_block_proc();
2051 rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
2052 }
Chris Fallinfcd88892015-01-13 18:14:39 -08002053
2054 return Qnil;
2055}
2056
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002057static void MessageBuilderContext_add_synthetic_oneofs(VALUE _self) {
2058 MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
Joshua Haberman6b759682020-04-23 12:54:25 -07002059 FileBuilderContext* file_context =
2060 ruby_to_FileBuilderContext(self->file_builder);
2061 size_t field_count, oneof_count;
2062 google_protobuf_FieldDescriptorProto** fields =
2063 google_protobuf_DescriptorProto_mutable_field(self->msg_proto, &field_count);
2064 const google_protobuf_OneofDescriptorProto*const* oneofs =
2065 google_protobuf_DescriptorProto_oneof_decl(self->msg_proto, &oneof_count);
2066 VALUE names = rb_hash_new();
2067 VALUE underscore = rb_str_new2("_");
2068 size_t i;
2069
2070 // We have to build a set of all names, to ensure that synthetic oneofs are
2071 // not creating conflicts.
2072 for (i = 0; i < field_count; i++) {
2073 upb_strview name = google_protobuf_FieldDescriptorProto_name(fields[i]);
2074 rb_hash_aset(names, rb_str_new(name.data, name.size), Qtrue);
2075 }
2076 for (i = 0; i < oneof_count; i++) {
2077 upb_strview name = google_protobuf_OneofDescriptorProto_name(oneofs[i]);
2078 rb_hash_aset(names, rb_str_new(name.data, name.size), Qtrue);
2079 }
2080
2081 for (i = 0; i < field_count; i++) {
2082 google_protobuf_OneofDescriptorProto* oneof_proto;
2083 VALUE oneof_name;
2084 upb_strview field_name;
2085
2086 if (!google_protobuf_FieldDescriptorProto_proto3_optional(fields[i])) {
2087 continue;
2088 }
2089
2090 // Prepend '_' until we are no longer conflicting.
2091 field_name = google_protobuf_FieldDescriptorProto_name(fields[i]);
2092 oneof_name = rb_str_new(field_name.data, field_name.size);
2093 while (rb_hash_lookup(names, oneof_name) != Qnil) {
2094 oneof_name = rb_str_plus(underscore, oneof_name);
2095 }
2096
2097 rb_hash_aset(names, oneof_name, Qtrue);
2098 google_protobuf_FieldDescriptorProto_set_oneof_index(fields[i],
2099 oneof_count++);
2100 oneof_proto = google_protobuf_DescriptorProto_add_oneof_decl(
2101 self->msg_proto, file_context->arena);
2102 google_protobuf_OneofDescriptorProto_set_name(
2103 oneof_proto, FileBuilderContext_strdup(self->file_builder, oneof_name));
2104 }
2105}
2106
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002107static void MessageBuilderContext_register(VALUE module) {
2108 VALUE klass = rb_define_class_under(
2109 module, "MessageBuilderContext", rb_cObject);
2110 rb_define_alloc_func(klass, MessageBuilderContext_alloc);
2111 rb_define_method(klass, "initialize",
2112 MessageBuilderContext_initialize, 2);
2113 rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
2114 rb_define_method(klass, "proto3_optional", MessageBuilderContext_proto3_optional, -1);
2115 rb_define_method(klass, "required", MessageBuilderContext_required, -1);
2116 rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
2117 rb_define_method(klass, "map", MessageBuilderContext_map, -1);
2118 rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
2119 rb_gc_register_address(&cMessageBuilderContext);
2120 cMessageBuilderContext = klass;
2121}
2122
Chris Fallinfcd88892015-01-13 18:14:39 -08002123// -----------------------------------------------------------------------------
2124// OneofBuilderContext.
2125// -----------------------------------------------------------------------------
2126
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002127typedef struct {
2128 int oneof_index;
2129 VALUE message_builder;
2130} OneofBuilderContext;
2131
2132static VALUE cOneofBuilderContext = Qnil;
Chris Fallinfcd88892015-01-13 18:14:39 -08002133
2134void OneofBuilderContext_mark(void* _self) {
2135 OneofBuilderContext* self = _self;
Joshua Haberman63f324a2019-08-14 22:41:37 +01002136 rb_gc_mark(self->message_builder);
Chris Fallinfcd88892015-01-13 18:14:39 -08002137}
2138
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002139static const rb_data_type_t OneofBuilderContext_type = {
2140 "Google::Protobuf::Internal::OneofBuilderContext",
2141 {OneofBuilderContext_mark, RUBY_DEFAULT_FREE, NULL},
2142 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
2143};
Chris Fallinfcd88892015-01-13 18:14:39 -08002144
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002145static OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE val) {
2146 OneofBuilderContext* ret;
2147 TypedData_Get_Struct(val, OneofBuilderContext, &OneofBuilderContext_type,
2148 ret);
Chris Fallinfcd88892015-01-13 18:14:39 -08002149 return ret;
2150}
2151
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002152static VALUE OneofBuilderContext_alloc(VALUE klass) {
2153 OneofBuilderContext* self = ALLOC(OneofBuilderContext);
2154 VALUE ret = TypedData_Wrap_Struct(klass, &OneofBuilderContext_type, self);
2155 self->oneof_index = 0;
2156 self->message_builder = Qnil;
2157 return ret;
Chris Fallinfcd88892015-01-13 18:14:39 -08002158}
2159
2160/*
2161 * call-seq:
Joshua Haberman63f324a2019-08-14 22:41:37 +01002162 * OneofBuilderContext.new(oneof_index, message_builder) => context
Chris Fallinfcd88892015-01-13 18:14:39 -08002163 *
2164 * Create a new oneof builder context around the given oneof descriptor and
2165 * builder context. This class is intended to serve as a DSL context to be used
2166 * with #instance_eval.
2167 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002168static VALUE OneofBuilderContext_initialize(VALUE _self, VALUE oneof_index,
2169 VALUE message_builder) {
2170 OneofBuilderContext* self = ruby_to_OneofBuilderContext(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002171 self->oneof_index = NUM2INT(oneof_index);
2172 self->message_builder = message_builder;
Chris Fallinfcd88892015-01-13 18:14:39 -08002173 return Qnil;
2174}
2175
2176/*
2177 * call-seq:
Harshit Choprad0535cc2017-08-25 12:11:15 -07002178 * OneofBuilderContext.optional(name, type, number, type_class = nil,
2179 * default_value = nil)
Chris Fallinfcd88892015-01-13 18:14:39 -08002180 *
2181 * Defines a new optional field in this oneof with the given type, tag number,
2182 * and type class (for message and enum fields). The type must be a Ruby symbol
2183 * (as accepted by FieldDescriptor#type=) and the type_class must be a string,
2184 * if present (as accepted by FieldDescriptor#submsg_name=).
2185 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002186static VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
2187 OneofBuilderContext* self = ruby_to_OneofBuilderContext(_self);
Harshit Choprad0535cc2017-08-25 12:11:15 -07002188 VALUE name, type, number;
2189 VALUE type_class, options = Qnil;
Chris Fallinfcd88892015-01-13 18:14:39 -08002190
Harshit Choprad0535cc2017-08-25 12:11:15 -07002191 rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
Chris Fallinfcd88892015-01-13 18:14:39 -08002192
Joshua Haberman63f324a2019-08-14 22:41:37 +01002193 msgdef_add_field(self->message_builder, UPB_LABEL_OPTIONAL, name, type,
Joshua Haberman6b759682020-04-23 12:54:25 -07002194 number, type_class, options, self->oneof_index, false);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002195
2196 return Qnil;
Chris Fallinfcd88892015-01-13 18:14:39 -08002197}
2198
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002199static void OneofBuilderContext_register(VALUE module) {
2200 VALUE klass = rb_define_class_under(
2201 module, "OneofBuilderContext", rb_cObject);
2202 rb_define_alloc_func(klass, OneofBuilderContext_alloc);
2203 rb_define_method(klass, "initialize",
2204 OneofBuilderContext_initialize, 2);
2205 rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
2206 rb_gc_register_address(&cOneofBuilderContext);
2207 cOneofBuilderContext = klass;
2208}
2209
Chris Fallin973f4252014-11-18 14:19:58 -08002210// -----------------------------------------------------------------------------
2211// EnumBuilderContext.
2212// -----------------------------------------------------------------------------
2213
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002214typedef struct {
2215 google_protobuf_EnumDescriptorProto* enum_proto;
2216 VALUE file_builder;
2217} EnumBuilderContext;
2218
2219static VALUE cEnumBuilderContext = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08002220
2221void EnumBuilderContext_mark(void* _self) {
2222 EnumBuilderContext* self = _self;
Joshua Haberman63f324a2019-08-14 22:41:37 +01002223 rb_gc_mark(self->file_builder);
Chris Fallin973f4252014-11-18 14:19:58 -08002224}
2225
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002226static const rb_data_type_t EnumBuilderContext_type = {
2227 "Google::Protobuf::Internal::EnumBuilderContext",
2228 {EnumBuilderContext_mark, RUBY_DEFAULT_FREE, NULL},
2229 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
2230};
Chris Fallin973f4252014-11-18 14:19:58 -08002231
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002232static EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE val) {
2233 EnumBuilderContext* ret;
2234 TypedData_Get_Struct(val, EnumBuilderContext, &EnumBuilderContext_type, ret);
Chris Fallin973f4252014-11-18 14:19:58 -08002235 return ret;
2236}
2237
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002238static VALUE EnumBuilderContext_alloc(VALUE klass) {
2239 EnumBuilderContext* self = ALLOC(EnumBuilderContext);
2240 VALUE ret = TypedData_Wrap_Struct(klass, &EnumBuilderContext_type, self);
2241 self->enum_proto = NULL;
2242 self->file_builder = Qnil;
2243 return ret;
Chris Fallin973f4252014-11-18 14:19:58 -08002244}
2245
2246/*
2247 * call-seq:
Joshua Haberman63f324a2019-08-14 22:41:37 +01002248 * EnumBuilderContext.new(file_builder) => context
Chris Fallin973f4252014-11-18 14:19:58 -08002249 *
2250 * Create a new builder context around the given enum descriptor. This class is
2251 * intended to serve as a DSL context to be used with #instance_eval.
2252 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002253static VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
2254 VALUE name) {
2255 EnumBuilderContext* self = ruby_to_EnumBuilderContext(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002256 FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
2257 google_protobuf_FileDescriptorProto* file_proto = file_builder->file_proto;
Chris Fallin973f4252014-11-18 14:19:58 -08002258
Joshua Haberman63f324a2019-08-14 22:41:37 +01002259 self->file_builder = _file_builder;
2260 self->enum_proto = google_protobuf_FileDescriptorProto_add_enum_type(
2261 file_proto, file_builder->arena);
2262
2263 google_protobuf_EnumDescriptorProto_set_name(
2264 self->enum_proto, FileBuilderContext_strdup(_file_builder, name));
2265
Chris Fallin973f4252014-11-18 14:19:58 -08002266 return Qnil;
2267}
2268
2269/*
2270 * call-seq:
2271 * EnumBuilder.add_value(name, number)
2272 *
2273 * Adds the given name => number mapping to the enum type. Name must be a Ruby
2274 * symbol.
2275 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002276static VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
2277 EnumBuilderContext* self = ruby_to_EnumBuilderContext(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002278 FileBuilderContext* file_builder =
2279 ruby_to_FileBuilderContext(self->file_builder);
2280 google_protobuf_EnumValueDescriptorProto* enum_value;
2281
2282 enum_value = google_protobuf_EnumDescriptorProto_add_value(
2283 self->enum_proto, file_builder->arena);
2284
2285 google_protobuf_EnumValueDescriptorProto_set_name(
2286 enum_value, FileBuilderContext_strdup_sym(self->file_builder, name));
2287 google_protobuf_EnumValueDescriptorProto_set_number(enum_value,
2288 NUM2INT(number));
2289
2290 return Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08002291}
2292
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002293static void EnumBuilderContext_register(VALUE module) {
2294 VALUE klass = rb_define_class_under(
2295 module, "EnumBuilderContext", rb_cObject);
2296 rb_define_alloc_func(klass, EnumBuilderContext_alloc);
2297 rb_define_method(klass, "initialize", EnumBuilderContext_initialize, 2);
2298 rb_define_method(klass, "value", EnumBuilderContext_value, 2);
2299 rb_gc_register_address(&cEnumBuilderContext);
2300 cEnumBuilderContext = klass;
Harshit Choprad0535cc2017-08-25 12:11:15 -07002301}
2302
Chris Fallin973f4252014-11-18 14:19:58 -08002303// -----------------------------------------------------------------------------
2304// Builder.
2305// -----------------------------------------------------------------------------
2306
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002307typedef struct {
2308 VALUE descriptor_pool;
2309 VALUE default_file_builder;
2310} Builder;
Chris Fallin973f4252014-11-18 14:19:58 -08002311
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002312static VALUE cBuilder = Qnil;
2313
2314static void Builder_mark(void* _self) {
Chris Fallin973f4252014-11-18 14:19:58 -08002315 Builder* self = _self;
Joshua Haberman63f324a2019-08-14 22:41:37 +01002316 rb_gc_mark(self->descriptor_pool);
2317 rb_gc_mark(self->default_file_builder);
Chris Fallin973f4252014-11-18 14:19:58 -08002318}
2319
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002320static const rb_data_type_t Builder_type = {
2321 "Google::Protobuf::Internal::Builder",
2322 {Builder_mark, RUBY_DEFAULT_FREE, NULL},
2323 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
2324};
Chris Fallin973f4252014-11-18 14:19:58 -08002325
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002326static Builder* ruby_to_Builder(VALUE val) {
2327 Builder* ret;
2328 TypedData_Get_Struct(val, Builder, &Builder_type, ret);
Chris Fallin973f4252014-11-18 14:19:58 -08002329 return ret;
2330}
2331
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002332static VALUE Builder_alloc(VALUE klass) {
2333 Builder* self = ALLOC(Builder);
2334 VALUE ret = TypedData_Wrap_Struct(klass, &Builder_type, self);
2335 self->descriptor_pool = Qnil;
2336 self->default_file_builder = Qnil;
2337 return ret;
Chris Fallin973f4252014-11-18 14:19:58 -08002338}
2339
2340/*
2341 * call-seq:
Joshua Haberman63f324a2019-08-14 22:41:37 +01002342 * Builder.new(descriptor_pool) => builder
Paul Yangcd5f49d2017-10-03 17:28:49 -07002343 *
Joshua Haberman63f324a2019-08-14 22:41:37 +01002344 * Creates a new Builder. A Builder can accumulate a set of new message and enum
2345 * descriptors and atomically register them into a pool in a way that allows for
2346 * (co)recursive type references.
Paul Yangcd5f49d2017-10-03 17:28:49 -07002347 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002348static VALUE Builder_initialize(VALUE _self, VALUE pool) {
2349 Builder* self = ruby_to_Builder(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002350 self->descriptor_pool = pool;
2351 self->default_file_builder = Qnil; // Created lazily if needed.
Harshit Choprad0535cc2017-08-25 12:11:15 -07002352 return Qnil;
2353}
2354
2355/*
2356 * call-seq:
2357 * Builder.add_file(name, options = nil, &block)
2358 *
2359 * Creates a new, file descriptor with the given name and options and invokes
2360 * the block in the context of a FileBuilderContext on that descriptor. The
2361 * block can then call FileBuilderContext#add_message or
2362 * FileBuilderContext#add_enum to define new messages or enums, respectively.
2363 *
2364 * This is the recommended, idiomatic way to build file descriptors.
2365 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002366static VALUE Builder_add_file(int argc, VALUE* argv, VALUE _self) {
2367 Builder* self = ruby_to_Builder(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002368 VALUE name, options;
2369 VALUE ctx;
2370 VALUE block;
Harshit Choprad0535cc2017-08-25 12:11:15 -07002371
Joshua Haberman63f324a2019-08-14 22:41:37 +01002372 rb_scan_args(argc, argv, "11", &name, &options);
2373
2374 {
2375 VALUE args[3] = { self->descriptor_pool, name, options };
2376 ctx = rb_class_new_instance(3, args, cFileBuilderContext);
2377 }
2378
2379 block = rb_block_proc();
2380 rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
2381 FileBuilderContext_build(ctx);
2382
Paul Yangcd5f49d2017-10-03 17:28:49 -07002383 return Qnil;
2384}
2385
Joshua Haberman63f324a2019-08-14 22:41:37 +01002386static VALUE Builder_get_default_file(VALUE _self) {
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002387 Builder* self = ruby_to_Builder(_self);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002388
2389 /* Lazily create only if legacy builder-level methods are called. */
2390 if (self->default_file_builder == Qnil) {
2391 VALUE name = rb_str_new2("ruby_default_file.proto");
2392 VALUE args [3] = { self->descriptor_pool, name, rb_hash_new() };
2393 self->default_file_builder =
2394 rb_class_new_instance(3, args, cFileBuilderContext);
2395 }
2396
2397 return self->default_file_builder;
2398}
2399
Paul Yangcd5f49d2017-10-03 17:28:49 -07002400/*
2401 * call-seq:
Chris Fallin973f4252014-11-18 14:19:58 -08002402 * Builder.add_message(name, &block)
2403 *
Harshit Choprad0535cc2017-08-25 12:11:15 -07002404 * Old and deprecated way to create a new descriptor.
2405 * See FileBuilderContext.add_message for the recommended way.
Chris Fallin973f4252014-11-18 14:19:58 -08002406 *
Harshit Choprad0535cc2017-08-25 12:11:15 -07002407 * Exists for backwards compatibility to allow building descriptor pool for
2408 * files generated by protoc which don't add messages within "add_file" block.
2409 * Descriptors created this way get assigned to a default empty FileDescriptor.
Chris Fallin973f4252014-11-18 14:19:58 -08002410 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002411static VALUE Builder_add_message(VALUE _self, VALUE name) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002412 VALUE file_builder = Builder_get_default_file(_self);
2413 rb_funcall_with_block(file_builder, rb_intern("add_message"), 1, &name,
2414 rb_block_proc());
Chris Fallin973f4252014-11-18 14:19:58 -08002415 return Qnil;
2416}
2417
2418/*
2419 * call-seq:
2420 * Builder.add_enum(name, &block)
2421 *
Harshit Choprad0535cc2017-08-25 12:11:15 -07002422 * Old and deprecated way to create a new enum descriptor.
2423 * See FileBuilderContext.add_enum for the recommended way.
Chris Fallin973f4252014-11-18 14:19:58 -08002424 *
Harshit Choprad0535cc2017-08-25 12:11:15 -07002425 * Exists for backwards compatibility to allow building descriptor pool for
2426 * files generated by protoc which don't add enums within "add_file" block.
2427 * Enum descriptors created this way get assigned to a default empty
2428 * FileDescriptor.
Chris Fallin973f4252014-11-18 14:19:58 -08002429 */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002430static VALUE Builder_add_enum(VALUE _self, VALUE name) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002431 VALUE file_builder = Builder_get_default_file(_self);
2432 rb_funcall_with_block(file_builder, rb_intern("add_enum"), 1, &name,
2433 rb_block_proc());
Chris Fallin973f4252014-11-18 14:19:58 -08002434 return Qnil;
2435}
2436
Joshua Haberman63f324a2019-08-14 22:41:37 +01002437/* This method is hidden from Ruby, and only called directly from
2438 * DescriptorPool_build(). */
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002439static VALUE Builder_build(VALUE _self) {
2440 Builder* self = ruby_to_Builder(_self);
Chris Fallin973f4252014-11-18 14:19:58 -08002441
Joshua Haberman63f324a2019-08-14 22:41:37 +01002442 if (self->default_file_builder != Qnil) {
2443 FileBuilderContext_build(self->default_file_builder);
2444 self->default_file_builder = Qnil;
Chris Fallin973f4252014-11-18 14:19:58 -08002445 }
2446
Chris Fallin973f4252014-11-18 14:19:58 -08002447 return Qnil;
2448}
Joshua Haberman63f324a2019-08-14 22:41:37 +01002449
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002450static void Builder_register(VALUE module) {
2451 VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
2452 rb_define_alloc_func(klass, Builder_alloc);
2453 rb_define_method(klass, "initialize", Builder_initialize, 1);
2454 rb_define_method(klass, "add_file", Builder_add_file, -1);
2455 rb_define_method(klass, "add_message", Builder_add_message, 1);
2456 rb_define_method(klass, "add_enum", Builder_add_enum, 1);
2457 rb_gc_register_address(&cBuilder);
2458 cBuilder = klass;
2459}
2460
Joshua Haberman63f324a2019-08-14 22:41:37 +01002461static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002462 DescriptorPool* descriptor_pool = ruby_to_DescriptorPool(_descriptor_pool);
Joshua Haberman63f324a2019-08-14 22:41:37 +01002463 VALUE key = ULL2NUM((intptr_t)ptr);
2464 VALUE def;
2465
2466 def = rb_hash_aref(descriptor_pool->def_to_descriptor, key);
2467
2468 if (ptr == NULL) {
2469 return Qnil;
2470 }
2471
2472 if (def == Qnil) {
2473 // Lazily create wrapper object.
2474 VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
2475 def = rb_class_new_instance(3, args, klass);
2476 rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
2477 }
2478
2479 return def;
2480}
2481
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002482static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002483 return get_def_obj(descriptor_pool, def, cDescriptor);
2484}
2485
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002486static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002487 return get_def_obj(descriptor_pool, def, cEnumDescriptor);
2488}
2489
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002490static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002491 return get_def_obj(descriptor_pool, def, cFieldDescriptor);
2492}
2493
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002494static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002495 return get_def_obj(descriptor_pool, def, cFileDescriptor);
2496}
2497
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002498static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def) {
Joshua Haberman63f324a2019-08-14 22:41:37 +01002499 return get_def_obj(descriptor_pool, def, cOneofDescriptor);
2500}
Joshua Haberman9abf6e22021-01-13 12:16:25 -08002501
2502// -----------------------------------------------------------------------------
2503// Shared functions
2504// -----------------------------------------------------------------------------
2505
2506// Functions exposed to other modules in defs.h.
2507
2508VALUE Descriptor_DefToClass(const upb_msgdef *m) {
2509 const upb_symtab *symtab = upb_filedef_symtab(upb_msgdef_file(m));
2510 VALUE pool = ObjectCache_Get(symtab);
2511 PBRUBY_ASSERT(pool != Qnil);
2512 VALUE desc_rb = get_msgdef_obj(pool, m);
2513 const Descriptor* desc = ruby_to_Descriptor(desc_rb);
2514 return desc->klass;
2515}
2516
2517const upb_msgdef *Descriptor_GetMsgDef(VALUE desc_rb) {
2518 const Descriptor* desc = ruby_to_Descriptor(desc_rb);
2519 return desc->msgdef;
2520}
2521
2522VALUE TypeInfo_InitArg(int argc, VALUE *argv, int skip_arg) {
2523 if (argc > skip_arg) {
2524 if (argc > 1 + skip_arg) {
2525 rb_raise(rb_eArgError, "Expected a maximum of %d arguments.", skip_arg + 1);
2526 }
2527 return argv[skip_arg];
2528 } else {
2529 return Qnil;
2530 }
2531}
2532
2533TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg,
2534 VALUE* type_class, VALUE* init_arg) {
2535 TypeInfo ret = {ruby_to_fieldtype(argv[skip_arg])};
2536
2537 if (ret.type == UPB_TYPE_MESSAGE || ret.type == UPB_TYPE_ENUM) {
2538 *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 2);
2539
2540 if (argc < 2 + skip_arg) {
2541 rb_raise(rb_eArgError, "Expected at least %d arguments for message/enum.",
2542 2 + skip_arg);
2543 }
2544
2545 VALUE klass = argv[1 + skip_arg];
2546 VALUE desc = MessageOrEnum_GetDescriptor(klass);
2547 *type_class = klass;
2548
2549 if (desc == Qnil) {
2550 rb_raise(rb_eArgError,
2551 "Type class has no descriptor. Please pass a "
2552 "class or enum as returned by the DescriptorPool.");
2553 }
2554
2555 if (ret.type == UPB_TYPE_MESSAGE) {
2556 ret.def.msgdef = ruby_to_Descriptor(desc)->msgdef;
2557 Message_CheckClass(klass);
2558 } else {
2559 PBRUBY_ASSERT(ret.type == UPB_TYPE_ENUM);
2560 ret.def.enumdef = ruby_to_EnumDescriptor(desc)->enumdef;
2561 }
2562 } else {
2563 *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 1);
2564 }
2565
2566 return ret;
2567}
2568
2569void Defs_register(VALUE module) {
2570 DescriptorPool_register(module);
2571 Descriptor_register(module);
2572 FileDescriptor_register(module);
2573 FieldDescriptor_register(module);
2574 OneofDescriptor_register(module);
2575 EnumDescriptor_register(module);
2576 FileBuilderContext_register(module);
2577 MessageBuilderContext_register(module);
2578 OneofBuilderContext_register(module);
2579 EnumBuilderContext_register(module);
2580 Builder_register(module);
2581
2582 rb_gc_register_address(&c_only_cookie);
2583 c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
2584}