blob: 63a61baffe67f95e97838ac8ec1d42550360ea6e [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001// Protocol Buffers - Google's data interchange format
2// Copyright 2014 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#include "protobuf.h"
32
33// -----------------------------------------------------------------------------
34// Class/module creation from msgdefs and enumdefs, respectively.
35// -----------------------------------------------------------------------------
36
37void* Message_data(void* msg) {
38 return ((uint8_t *)msg) + sizeof(MessageHeader);
39}
40
41void Message_mark(void* _self) {
42 MessageHeader* self = (MessageHeader *)_self;
43 layout_mark(self->descriptor->layout, Message_data(self));
44}
45
46void Message_free(void* self) {
Austin Schuh40c16522018-10-28 20:27:54 -070047 stringsink* unknown = ((MessageHeader *)self)->unknown_fields;
48 if (unknown != NULL) {
49 stringsink_uninit(unknown);
50 free(unknown);
51 }
Brian Silverman9c614bc2016-02-15 20:20:02 -050052 xfree(self);
53}
54
55rb_data_type_t Message_type = {
56 "Message",
57 { Message_mark, Message_free, NULL },
58};
59
60VALUE Message_alloc(VALUE klass) {
61 VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
62 Descriptor* desc = ruby_to_Descriptor(descriptor);
63 MessageHeader* msg = (MessageHeader*)ALLOC_N(
64 uint8_t, sizeof(MessageHeader) + desc->layout->size);
65 VALUE ret;
66
67 memset(Message_data(msg), 0, desc->layout->size);
68
69 // We wrap first so that everything in the message object is GC-rooted in case
70 // a collection happens during object creation in layout_init().
71 ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
72 msg->descriptor = desc;
73 rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
74
Austin Schuh40c16522018-10-28 20:27:54 -070075 msg->unknown_fields = NULL;
76
Brian Silverman9c614bc2016-02-15 20:20:02 -050077 layout_init(desc->layout, Message_data(msg));
78
79 return ret;
80}
81
82static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
83 upb_oneof_iter it;
84 size_t case_ofs;
85 uint32_t oneof_case;
86 const upb_fielddef* first_field;
87 const upb_fielddef* f;
88
89 // If no fields in the oneof, always nil.
90 if (upb_oneofdef_numfields(o) == 0) {
91 return Qnil;
92 }
93 // Grab the first field in the oneof so we can get its layout info to find the
94 // oneof_case field.
95 upb_oneof_begin(&it, o);
96 assert(!upb_oneof_done(&it));
97 first_field = upb_oneof_iter_field(&it);
98 assert(upb_fielddef_containingoneof(first_field) != NULL);
99
100 case_ofs =
101 self->descriptor->layout->
102 fields[upb_fielddef_index(first_field)].case_offset;
103 oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
104
105 if (oneof_case == ONEOF_CASE_NONE) {
106 return Qnil;
107 }
108
109 // oneof_case is a field index, so find that field.
110 f = upb_oneofdef_itof(o, oneof_case);
111 assert(f != NULL);
112
113 return ID2SYM(rb_intern(upb_fielddef_name(f)));
114}
115
116/*
117 * call-seq:
118 * Message.method_missing(*args)
119 *
120 * Provides accessors and setters for message fields according to their field
121 * names. For any field whose name does not conflict with a built-in method, an
122 * accessor is provided with the same name as the field, and a setter is
123 * provided with the name of the field plus the '=' suffix. Thus, given a
124 * message instance 'msg' with field 'foo', the following code is valid:
125 *
126 * msg.foo = 42
127 * puts msg.foo
128 *
129 * This method also provides read-only accessors for oneofs. If a oneof exists
130 * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
131 * the name of the field in that oneof that is currently set, or nil if none.
132 */
133VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
134 MessageHeader* self;
135 VALUE method_name, method_str;
136 char* name;
137 size_t name_len;
138 bool setter;
139 const upb_oneofdef* o;
140 const upb_fielddef* f;
141
142 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
143 if (argc < 1) {
144 rb_raise(rb_eArgError, "Expected method name as first argument.");
145 }
146 method_name = argv[0];
147 if (!SYMBOL_P(method_name)) {
148 rb_raise(rb_eArgError, "Expected symbol as method name.");
149 }
150 method_str = rb_id2str(SYM2ID(method_name));
151 name = RSTRING_PTR(method_str);
152 name_len = RSTRING_LEN(method_str);
153 setter = false;
154
155 // Setters have names that end in '='.
156 if (name[name_len - 1] == '=') {
157 setter = true;
158 name_len--;
159 }
160
Austin Schuh40c16522018-10-28 20:27:54 -0700161 // See if this name corresponds to either a oneof or field in this message.
162 if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
163 &o)) {
164 return rb_call_super(argc, argv);
165 }
166
Brian Silverman9c614bc2016-02-15 20:20:02 -0500167 if (o != NULL) {
Austin Schuh40c16522018-10-28 20:27:54 -0700168 // This is a oneof -- return which field inside the oneof is set.
Brian Silverman9c614bc2016-02-15 20:20:02 -0500169 if (setter) {
170 rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
171 }
172 return which_oneof_field(self, o);
Austin Schuh40c16522018-10-28 20:27:54 -0700173 } else {
174 // This is a field -- get or set the field's value.
175 assert(f);
176 if (setter) {
177 if (argc < 2) {
178 rb_raise(rb_eArgError, "No value provided to setter.");
179 }
180 layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
181 return Qnil;
182 } else {
183 return layout_get(self->descriptor->layout, Message_data(self), f);
184 }
185 }
186}
187
188VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
189 MessageHeader* self;
190 VALUE method_name, method_str;
191 char* name;
192 size_t name_len;
193 bool setter;
194 const upb_oneofdef* o;
195 const upb_fielddef* f;
196
197 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
198 if (argc < 1) {
199 rb_raise(rb_eArgError, "Expected method name as first argument.");
200 }
201 method_name = argv[0];
202 if (!SYMBOL_P(method_name)) {
203 rb_raise(rb_eArgError, "Expected symbol as method name.");
204 }
205 method_str = rb_id2str(SYM2ID(method_name));
206 name = RSTRING_PTR(method_str);
207 name_len = RSTRING_LEN(method_str);
208 setter = false;
209
210 // Setters have names that end in '='.
211 if (name[name_len - 1] == '=') {
212 setter = true;
213 name_len--;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500214 }
215
Austin Schuh40c16522018-10-28 20:27:54 -0700216 // See if this name corresponds to either a oneof or field in this message.
217 if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
218 &o)) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500219 return rb_call_super(argc, argv);
220 }
Austin Schuh40c16522018-10-28 20:27:54 -0700221 if (o != NULL) {
222 return setter ? Qfalse : Qtrue;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500223 }
Austin Schuh40c16522018-10-28 20:27:54 -0700224 return Qtrue;
225}
226
227VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
228 const upb_def *d = upb_fielddef_subdef(f);
229 assert(d != NULL);
230
231 VALUE descriptor = get_def_obj(d);
232 VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
233
234 VALUE args[1] = { hash };
235 return rb_class_new_instance(1, args, msgclass);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500236}
237
238int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
239 MessageHeader* self;
Austin Schuh40c16522018-10-28 20:27:54 -0700240 char *name;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500241 const upb_fielddef* f;
242 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
243
Austin Schuh40c16522018-10-28 20:27:54 -0700244 if (TYPE(key) == T_STRING) {
245 name = RSTRING_PTR(key);
246 } else if (TYPE(key) == T_SYMBOL) {
247 name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
248 } else {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500249 rb_raise(rb_eArgError,
Austin Schuh40c16522018-10-28 20:27:54 -0700250 "Expected string or symbols as hash keys when initializing proto from hash.");
Brian Silverman9c614bc2016-02-15 20:20:02 -0500251 }
252
Brian Silverman9c614bc2016-02-15 20:20:02 -0500253 f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
254 if (f == NULL) {
255 rb_raise(rb_eArgError,
256 "Unknown field name '%s' in initialization map entry.", name);
257 }
258
259 if (is_map_field(f)) {
260 VALUE map;
261
262 if (TYPE(val) != T_HASH) {
263 rb_raise(rb_eArgError,
264 "Expected Hash object as initializer value for map field '%s'.", name);
265 }
266 map = layout_get(self->descriptor->layout, Message_data(self), f);
267 Map_merge_into_self(map, val);
268 } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
269 VALUE ary;
270
271 if (TYPE(val) != T_ARRAY) {
272 rb_raise(rb_eArgError,
273 "Expected array as initializer value for repeated field '%s'.", name);
274 }
275 ary = layout_get(self->descriptor->layout, Message_data(self), f);
276 for (int i = 0; i < RARRAY_LEN(val); i++) {
Austin Schuh40c16522018-10-28 20:27:54 -0700277 VALUE entry = rb_ary_entry(val, i);
278 if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
279 entry = create_submsg_from_hash(f, entry);
280 }
281
282 RepeatedField_push(ary, entry);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500283 }
284 } else {
Austin Schuh40c16522018-10-28 20:27:54 -0700285 if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
286 val = create_submsg_from_hash(f, val);
287 }
288
Brian Silverman9c614bc2016-02-15 20:20:02 -0500289 layout_set(self->descriptor->layout, Message_data(self), f, val);
290 }
291 return 0;
292}
293
294/*
295 * call-seq:
296 * Message.new(kwargs) => new_message
297 *
298 * Creates a new instance of the given message class. Keyword arguments may be
299 * provided with keywords corresponding to field names.
300 *
301 * Note that no literal Message class exists. Only concrete classes per message
302 * type exist, as provided by the #msgclass method on Descriptors after they
303 * have been added to a pool. The method definitions described here on the
304 * Message class are provided on each concrete message class.
305 */
306VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
307 VALUE hash_args;
308
309 if (argc == 0) {
310 return Qnil;
311 }
312 if (argc != 1) {
313 rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
314 }
315 hash_args = argv[0];
316 if (TYPE(hash_args) != T_HASH) {
317 rb_raise(rb_eArgError, "Expected hash arguments.");
318 }
319
320 rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
321 return Qnil;
322}
323
324/*
325 * call-seq:
326 * Message.dup => new_message
327 *
328 * Performs a shallow copy of this message and returns the new copy.
329 */
330VALUE Message_dup(VALUE _self) {
331 MessageHeader* self;
332 VALUE new_msg;
333 MessageHeader* new_msg_self;
334 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
335
336 new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
337 TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
338
339 layout_dup(self->descriptor->layout,
340 Message_data(new_msg_self),
341 Message_data(self));
342
343 return new_msg;
344}
345
346// Internal only; used by Google::Protobuf.deep_copy.
347VALUE Message_deep_copy(VALUE _self) {
348 MessageHeader* self;
349 MessageHeader* new_msg_self;
350 VALUE new_msg;
351 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
352
353 new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
354 TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
355
356 layout_deep_copy(self->descriptor->layout,
357 Message_data(new_msg_self),
358 Message_data(self));
359
360 return new_msg;
361}
362
363/*
364 * call-seq:
365 * Message.==(other) => boolean
366 *
367 * Performs a deep comparison of this message with another. Messages are equal
368 * if they have the same type and if each field is equal according to the :==
369 * method's semantics (a more efficient comparison may actually be done if the
370 * field is of a primitive type).
371 */
372VALUE Message_eq(VALUE _self, VALUE _other) {
373 MessageHeader* self;
374 MessageHeader* other;
Austin Schuh40c16522018-10-28 20:27:54 -0700375 if (TYPE(_self) != TYPE(_other)) {
376 return Qfalse;
377 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500378 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
379 TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
380
381 if (self->descriptor != other->descriptor) {
382 return Qfalse;
383 }
384
385 return layout_eq(self->descriptor->layout,
386 Message_data(self),
387 Message_data(other));
388}
389
390/*
391 * call-seq:
392 * Message.hash => hash_value
393 *
394 * Returns a hash value that represents this message's field values.
395 */
396VALUE Message_hash(VALUE _self) {
397 MessageHeader* self;
398 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
399
400 return layout_hash(self->descriptor->layout, Message_data(self));
401}
402
403/*
404 * call-seq:
405 * Message.inspect => string
406 *
407 * Returns a human-readable string representing this message. It will be
408 * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
409 * field's value is represented according to its own #inspect method.
410 */
411VALUE Message_inspect(VALUE _self) {
412 MessageHeader* self;
413 VALUE str;
414 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
415
416 str = rb_str_new2("<");
417 str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
418 str = rb_str_cat2(str, ": ");
419 str = rb_str_append(str, layout_inspect(
420 self->descriptor->layout, Message_data(self)));
421 str = rb_str_cat2(str, ">");
422 return str;
423}
424
Austin Schuh40c16522018-10-28 20:27:54 -0700425/*
426 * call-seq:
427 * Message.to_h => {}
428 *
429 * Returns the message as a Ruby Hash object, with keys as symbols.
430 */
Brian Silverman9c614bc2016-02-15 20:20:02 -0500431VALUE Message_to_h(VALUE _self) {
432 MessageHeader* self;
433 VALUE hash;
434 upb_msg_field_iter it;
435 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
436
437 hash = rb_hash_new();
438
439 for (upb_msg_field_begin(&it, self->descriptor->msgdef);
440 !upb_msg_field_done(&it);
441 upb_msg_field_next(&it)) {
442 const upb_fielddef* field = upb_msg_iter_field(&it);
443 VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
444 field);
445 VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
Austin Schuh40c16522018-10-28 20:27:54 -0700446 if (upb_fielddef_ismap(field)) {
447 msg_value = Map_to_h(msg_value);
448 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500449 msg_value = RepeatedField_to_ary(msg_value);
Austin Schuh40c16522018-10-28 20:27:54 -0700450
451 if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
452 for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
453 VALUE elem = rb_ary_entry(msg_value, i);
454 rb_ary_store(msg_value, i, Message_to_h(elem));
455 }
456 }
457 } else if (msg_value != Qnil &&
458 upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
459 msg_value = Message_to_h(msg_value);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500460 }
461 rb_hash_aset(hash, msg_key, msg_value);
462 }
463 return hash;
464}
465
466
467
468/*
469 * call-seq:
470 * Message.[](index) => value
471 *
472 * Accesses a field's value by field name. The provided field name should be a
473 * string.
474 */
475VALUE Message_index(VALUE _self, VALUE field_name) {
476 MessageHeader* self;
477 const upb_fielddef* field;
478 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
479 Check_Type(field_name, T_STRING);
480 field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
481 if (field == NULL) {
482 return Qnil;
483 }
484 return layout_get(self->descriptor->layout, Message_data(self), field);
485}
486
487/*
488 * call-seq:
489 * Message.[]=(index, value)
490 *
491 * Sets a field's value by field name. The provided field name should be a
492 * string.
493 */
494VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
495 MessageHeader* self;
496 const upb_fielddef* field;
497 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
498 Check_Type(field_name, T_STRING);
499 field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
500 if (field == NULL) {
501 rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
502 }
503 layout_set(self->descriptor->layout, Message_data(self), field, value);
504 return Qnil;
505}
506
507/*
508 * call-seq:
509 * Message.descriptor => descriptor
510 *
511 * Class method that returns the Descriptor instance corresponding to this
512 * message class's type.
513 */
514VALUE Message_descriptor(VALUE klass) {
515 return rb_ivar_get(klass, descriptor_instancevar_interned);
516}
517
518VALUE build_class_from_descriptor(Descriptor* desc) {
519 const char *name;
520 VALUE klass;
521
522 if (desc->layout == NULL) {
523 desc->layout = create_layout(desc->msgdef);
524 }
525 if (desc->fill_method == NULL) {
526 desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
527 }
528
529 name = upb_msgdef_fullname(desc->msgdef);
530 if (name == NULL) {
531 rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
532 }
533
534 klass = rb_define_class_id(
535 // Docs say this parameter is ignored. User will assign return value to
536 // their own toplevel constant class name.
537 rb_intern("Message"),
538 rb_cObject);
539 rb_ivar_set(klass, descriptor_instancevar_interned,
540 get_def_obj(desc->msgdef));
541 rb_define_alloc_func(klass, Message_alloc);
542 rb_require("google/protobuf/message_exts");
Austin Schuh40c16522018-10-28 20:27:54 -0700543 rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
Brian Silverman9c614bc2016-02-15 20:20:02 -0500544 rb_extend_object(
Austin Schuh40c16522018-10-28 20:27:54 -0700545 klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
Brian Silverman9c614bc2016-02-15 20:20:02 -0500546
547 rb_define_method(klass, "method_missing",
548 Message_method_missing, -1);
Austin Schuh40c16522018-10-28 20:27:54 -0700549 rb_define_method(klass, "respond_to_missing?",
550 Message_respond_to_missing, -1);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500551 rb_define_method(klass, "initialize", Message_initialize, -1);
552 rb_define_method(klass, "dup", Message_dup, 0);
553 // Also define #clone so that we don't inherit Object#clone.
554 rb_define_method(klass, "clone", Message_dup, 0);
555 rb_define_method(klass, "==", Message_eq, 1);
556 rb_define_method(klass, "hash", Message_hash, 0);
557 rb_define_method(klass, "to_h", Message_to_h, 0);
558 rb_define_method(klass, "to_hash", Message_to_h, 0);
559 rb_define_method(klass, "inspect", Message_inspect, 0);
560 rb_define_method(klass, "[]", Message_index, 1);
561 rb_define_method(klass, "[]=", Message_index_set, 2);
562 rb_define_singleton_method(klass, "decode", Message_decode, 1);
563 rb_define_singleton_method(klass, "encode", Message_encode, 1);
564 rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
Austin Schuh40c16522018-10-28 20:27:54 -0700565 rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500566 rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
567
568 return klass;
569}
570
571/*
572 * call-seq:
573 * Enum.lookup(number) => name
574 *
575 * This module method, provided on each generated enum module, looks up an enum
576 * value by number and returns its name as a Ruby symbol, or nil if not found.
577 */
578VALUE enum_lookup(VALUE self, VALUE number) {
579 int32_t num = NUM2INT(number);
580 VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
581 EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
582
583 const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
584 if (name == NULL) {
585 return Qnil;
586 } else {
587 return ID2SYM(rb_intern(name));
588 }
589}
590
591/*
592 * call-seq:
593 * Enum.resolve(name) => number
594 *
595 * This module method, provided on each generated enum module, looks up an enum
596 * value by name (as a Ruby symbol) and returns its name, or nil if not found.
597 */
598VALUE enum_resolve(VALUE self, VALUE sym) {
599 const char* name = rb_id2name(SYM2ID(sym));
600 VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
601 EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
602
603 int32_t num = 0;
604 bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
605 if (!found) {
606 return Qnil;
607 } else {
608 return INT2NUM(num);
609 }
610}
611
612/*
613 * call-seq:
614 * Enum.descriptor
615 *
616 * This module method, provided on each generated enum module, returns the
617 * EnumDescriptor corresponding to this enum type.
618 */
619VALUE enum_descriptor(VALUE self) {
620 return rb_ivar_get(self, descriptor_instancevar_interned);
621}
622
623VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
624 VALUE mod = rb_define_module_id(
625 rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
626
627 upb_enum_iter it;
628 for (upb_enum_begin(&it, enumdesc->enumdef);
629 !upb_enum_done(&it);
630 upb_enum_next(&it)) {
631 const char* name = upb_enum_iter_name(&it);
632 int32_t value = upb_enum_iter_number(&it);
633 if (name[0] < 'A' || name[0] > 'Z') {
634 rb_raise(rb_eTypeError,
635 "Enum value '%s' does not start with an uppercase letter "
636 "as is required for Ruby constants.",
637 name);
638 }
639 rb_define_const(mod, name, INT2NUM(value));
640 }
641
642 rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
643 rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
644 rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
645 rb_ivar_set(mod, descriptor_instancevar_interned,
646 get_def_obj(enumdesc->enumdef));
647
648 return mod;
649}
650
651/*
652 * call-seq:
653 * Google::Protobuf.deep_copy(obj) => copy_of_obj
654 *
655 * Performs a deep copy of a RepeatedField instance, a Map instance, or a
656 * message object, recursively copying its members.
657 */
658VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
659 VALUE klass = CLASS_OF(obj);
660 if (klass == cRepeatedField) {
661 return RepeatedField_deep_copy(obj);
662 } else if (klass == cMap) {
663 return Map_deep_copy(obj);
664 } else {
665 return Message_deep_copy(obj);
666 }
667}