• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "protobuf.h"
32 
33 // -----------------------------------------------------------------------------
34 // Class/module creation from msgdefs and enumdefs, respectively.
35 // -----------------------------------------------------------------------------
36 
Message_data(void * msg)37 void* Message_data(void* msg) {
38   return ((uint8_t *)msg) + sizeof(MessageHeader);
39 }
40 
Message_mark(void * _self)41 void Message_mark(void* _self) {
42   MessageHeader* self = (MessageHeader *)_self;
43   layout_mark(self->descriptor->layout, Message_data(self));
44 }
45 
Message_free(void * self)46 void Message_free(void* self) {
47   stringsink* unknown = ((MessageHeader *)self)->unknown_fields;
48   if (unknown != NULL) {
49     stringsink_uninit(unknown);
50     free(unknown);
51   }
52   xfree(self);
53 }
54 
55 rb_data_type_t Message_type = {
56   "Message",
57   { Message_mark, Message_free, NULL },
58 };
59 
Message_alloc(VALUE klass)60 VALUE Message_alloc(VALUE klass) {
61   VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
62   Descriptor* desc = ruby_to_Descriptor(descriptor);
63   MessageHeader* msg;
64   VALUE ret;
65 
66   if (desc->layout == NULL) {
67     create_layout(desc);
68   }
69 
70   msg = (void*)ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
71   msg->descriptor = desc;
72   msg->unknown_fields = NULL;
73   memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
74 
75   ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
76   rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
77 
78   return ret;
79 }
80 
which_oneof_field(MessageHeader * self,const upb_oneofdef * o)81 static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
82   uint32_t oneof_case;
83   const upb_fielddef* f;
84 
85   oneof_case =
86       slot_read_oneof_case(self->descriptor->layout, Message_data(self), o);
87 
88   if (oneof_case == ONEOF_CASE_NONE) {
89     return NULL;
90   }
91 
92   // oneof_case is a field index, so find that field.
93   f = upb_oneofdef_itof(o, oneof_case);
94   assert(f != NULL);
95 
96   return f;
97 }
98 
99 enum {
100   METHOD_UNKNOWN = 0,
101   METHOD_GETTER = 1,
102   METHOD_SETTER = 2,
103   METHOD_CLEAR = 3,
104   METHOD_PRESENCE = 4,
105   METHOD_ENUM_GETTER = 5,
106   METHOD_WRAPPER_GETTER = 6,
107   METHOD_WRAPPER_SETTER = 7
108 };
109 
110 // Check if the field is a well known wrapper type
is_wrapper_type_field(const upb_fielddef * field)111 bool is_wrapper_type_field(const upb_fielddef* field) {
112   const upb_msgdef *m;
113   if (upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
114     return false;
115   }
116   m = upb_fielddef_msgsubdef(field);
117   switch (upb_msgdef_wellknowntype(m)) {
118     case UPB_WELLKNOWN_DOUBLEVALUE:
119     case UPB_WELLKNOWN_FLOATVALUE:
120     case UPB_WELLKNOWN_INT64VALUE:
121     case UPB_WELLKNOWN_UINT64VALUE:
122     case UPB_WELLKNOWN_INT32VALUE:
123     case UPB_WELLKNOWN_UINT32VALUE:
124     case UPB_WELLKNOWN_STRINGVALUE:
125     case UPB_WELLKNOWN_BYTESVALUE:
126     case UPB_WELLKNOWN_BOOLVALUE:
127       return true;
128     default:
129       return false;
130   }
131 }
132 
133 // Get a new Ruby wrapper type and set the initial value
ruby_wrapper_type(VALUE type_class,VALUE value)134 VALUE ruby_wrapper_type(VALUE type_class, VALUE value) {
135   if (value != Qnil) {
136     VALUE hash = rb_hash_new();
137     rb_hash_aset(hash, rb_str_new2("value"), value);
138     {
139       VALUE args[1] = {hash};
140       return rb_class_new_instance(1, args, type_class);
141     }
142   }
143   return Qnil;
144 }
145 
extract_method_call(VALUE method_name,MessageHeader * self,const upb_fielddef ** f,const upb_oneofdef ** o)146 static int extract_method_call(VALUE method_name, MessageHeader* self,
147                             const upb_fielddef **f, const upb_oneofdef **o) {
148   VALUE method_str;
149   char* name;
150   size_t name_len;
151   int accessor_type;
152   const upb_oneofdef* test_o;
153   const upb_fielddef* test_f;
154   bool has_field;
155 
156   Check_Type(method_name, T_SYMBOL);
157 
158   method_str = rb_id2str(SYM2ID(method_name));
159   name = RSTRING_PTR(method_str);
160   name_len = RSTRING_LEN(method_str);
161 
162   if (name[name_len - 1] == '=') {
163     accessor_type = METHOD_SETTER;
164     name_len--;
165     // We want to ensure if the proto has something named clear_foo or has_foo?,
166     // we don't strip the prefix.
167   } else if (strncmp("clear_", name, 6) == 0 &&
168              !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
169                                     &test_f, &test_o)) {
170     accessor_type = METHOD_CLEAR;
171     name = name + 6;
172     name_len = name_len - 6;
173   } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
174              !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
175                                     &test_f, &test_o)) {
176     accessor_type = METHOD_PRESENCE;
177     name = name + 4;
178     name_len = name_len - 5;
179   } else {
180     accessor_type = METHOD_GETTER;
181   }
182 
183   has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
184                                     &test_f, &test_o);
185 
186   // Look for wrapper type accessor of the form <field_name>_as_value
187   if (!has_field &&
188       (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
189       name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
190     const upb_oneofdef* test_o_wrapper;
191     const upb_fielddef* test_f_wrapper;
192     char wrapper_field_name[name_len - 8];
193 
194     // Find the field name
195     strncpy(wrapper_field_name, name, name_len - 9);
196     wrapper_field_name[name_len - 9] = '\0';
197 
198     // Check if field exists and is a wrapper type
199     if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
200                               name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
201         is_wrapper_type_field(test_f_wrapper)) {
202       // It does exist!
203       has_field = true;
204       if (accessor_type == METHOD_SETTER) {
205         accessor_type = METHOD_WRAPPER_SETTER;
206       } else {
207         accessor_type = METHOD_WRAPPER_GETTER;
208       }
209       test_o = test_o_wrapper;
210       test_f = test_f_wrapper;
211     }
212   }
213 
214   // Look for enum accessor of the form <enum_name>_const
215   if (!has_field && accessor_type == METHOD_GETTER &&
216       name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
217     const upb_oneofdef* test_o_enum;
218     const upb_fielddef* test_f_enum;
219     char enum_name[name_len - 5];
220 
221     // Find enum field name
222     strncpy(enum_name, name, name_len - 6);
223     enum_name[name_len - 6] = '\0';
224 
225     // Check if enum field exists
226     if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
227                                              &test_f_enum, &test_o_enum) &&
228         upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
229       // It does exist!
230       has_field = true;
231       accessor_type = METHOD_ENUM_GETTER;
232       test_o = test_o_enum;
233       test_f = test_f_enum;
234     }
235   }
236 
237   // Verify the name corresponds to a oneof or field in this message.
238   if (!has_field) {
239     return METHOD_UNKNOWN;
240   }
241 
242   // Method calls like 'has_foo?' are not allowed if field "foo" does not have
243   // a hasbit (e.g. repeated fields or non-message type fields for proto3
244   // syntax).
245   if (accessor_type == METHOD_PRESENCE && test_f != NULL) {
246     if (!upb_fielddef_haspresence(test_f)) return METHOD_UNKNOWN;
247 
248     // TODO(haberman): remove this case, allow for proto3 oneofs.
249     if (upb_fielddef_realcontainingoneof(test_f) &&
250         upb_filedef_syntax(upb_fielddef_file(test_f)) == UPB_SYNTAX_PROTO3) {
251       return METHOD_UNKNOWN;
252     }
253   }
254 
255   *o = test_o;
256   *f = test_f;
257   return accessor_type;
258 }
259 
260 /*
261  * call-seq:
262  *     Message.method_missing(*args)
263  *
264  * Provides accessors and setters and methods to clear and check for presence of
265  * message fields according to their field names.
266  *
267  * For any field whose name does not conflict with a built-in method, an
268  * accessor is provided with the same name as the field, and a setter is
269  * provided with the name of the field plus the '=' suffix. Thus, given a
270  * message instance 'msg' with field 'foo', the following code is valid:
271  *
272  *     msg.foo = 42
273  *     puts msg.foo
274  *
275  * This method also provides read-only accessors for oneofs. If a oneof exists
276  * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
277  * the name of the field in that oneof that is currently set, or nil if none.
278  *
279  * It also provides methods of the form 'clear_fieldname' to clear the value
280  * of the field 'fieldname'. For basic data types, this will set the default
281  * value of the field.
282  *
283  * Additionally, it provides methods of the form 'has_fieldname?', which returns
284  * true if the field 'fieldname' is set in the message object, else false. For
285  * 'proto3' syntax, calling this for a basic type field will result in an error.
286  */
Message_method_missing(int argc,VALUE * argv,VALUE _self)287 VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
288   MessageHeader* self;
289   const upb_oneofdef* o;
290   const upb_fielddef* f;
291   int accessor_type;
292 
293   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
294   if (argc < 1) {
295     rb_raise(rb_eArgError, "Expected method name as first argument.");
296   }
297 
298   accessor_type = extract_method_call(argv[0], self, &f, &o);
299   if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
300     return rb_call_super(argc, argv);
301   } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
302     if (argc != 2) {
303       rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
304     }
305     rb_check_frozen(_self);
306   } else if (argc != 1) {
307     rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
308   }
309 
310   // Return which of the oneof fields are set
311   if (o != NULL) {
312     const upb_fielddef* oneof_field = which_oneof_field(self, o);
313 
314     if (accessor_type == METHOD_SETTER) {
315       rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
316     }
317 
318     if (accessor_type == METHOD_PRESENCE) {
319       return oneof_field == NULL ? Qfalse : Qtrue;
320     } else if (accessor_type == METHOD_CLEAR) {
321       if (oneof_field != NULL) {
322         layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
323       }
324       return Qnil;
325     } else {
326       // METHOD_ACCESSOR
327       return oneof_field == NULL ? Qnil :
328         ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
329     }
330   // Otherwise we're operating on a single proto field
331   } else if (accessor_type == METHOD_SETTER) {
332     layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
333     return Qnil;
334   } else if (accessor_type == METHOD_CLEAR) {
335     layout_clear(self->descriptor->layout, Message_data(self), f);
336     return Qnil;
337   } else if (accessor_type == METHOD_PRESENCE) {
338     return layout_has(self->descriptor->layout, Message_data(self), f);
339   } else if (accessor_type == METHOD_WRAPPER_GETTER) {
340     VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
341     switch (TYPE(value)) {
342       case T_DATA:
343         return rb_funcall(value, rb_intern("value"), 0);
344       case T_NIL:
345         return Qnil;
346       default:
347         return value;
348     }
349   } else if (accessor_type == METHOD_WRAPPER_SETTER) {
350     VALUE wrapper = ruby_wrapper_type(
351         field_type_class(self->descriptor->layout, f), argv[1]);
352     layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
353     return Qnil;
354   } else if (accessor_type == METHOD_ENUM_GETTER) {
355     VALUE enum_type = field_type_class(self->descriptor->layout, f);
356     VALUE method = rb_intern("const_get");
357     VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
358 
359     // Map repeated fields to a new type with ints
360     if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
361       int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
362       int i;
363       VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
364       VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
365       for (i = 0; i < array_size; i++) {
366         VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
367                                  rb_intern("at"), 1, INT2NUM(i)));
368         rb_funcall(array, rb_intern("push"), 1, entry);
369       }
370       return array;
371     }
372     // Convert the value for singular fields
373     return rb_funcall(enum_type, method, 1, raw_value);
374   } else {
375     return layout_get(self->descriptor->layout, Message_data(self), f);
376   }
377 }
378 
379 
Message_respond_to_missing(int argc,VALUE * argv,VALUE _self)380 VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
381   MessageHeader* self;
382   const upb_oneofdef* o;
383   const upb_fielddef* f;
384   int accessor_type;
385 
386   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
387   if (argc < 1) {
388     rb_raise(rb_eArgError, "Expected method name as first argument.");
389   }
390 
391   accessor_type = extract_method_call(argv[0], self, &f, &o);
392   if (accessor_type == METHOD_UNKNOWN) {
393     return rb_call_super(argc, argv);
394   } else if (o != NULL) {
395     return accessor_type == METHOD_SETTER ? Qfalse : Qtrue;
396   } else {
397     return Qtrue;
398   }
399 }
400 
create_submsg_from_hash(const MessageLayout * layout,const upb_fielddef * f,VALUE hash)401 VALUE create_submsg_from_hash(const MessageLayout* layout,
402                               const upb_fielddef* f, VALUE hash) {
403   VALUE args[1] = { hash };
404   return rb_class_new_instance(1, args, field_type_class(layout, f));
405 }
406 
Message_initialize_kwarg(VALUE key,VALUE val,VALUE _self)407 int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
408   MessageHeader* self;
409   char *name;
410   const upb_fielddef* f;
411   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
412 
413   if (TYPE(key) == T_STRING) {
414     name = RSTRING_PTR(key);
415   } else if (TYPE(key) == T_SYMBOL) {
416     name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
417   } else {
418     rb_raise(rb_eArgError,
419              "Expected string or symbols as hash keys when initializing proto from hash.");
420   }
421 
422   f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
423   if (f == NULL) {
424     rb_raise(rb_eArgError,
425              "Unknown field name '%s' in initialization map entry.", name);
426   }
427 
428   if (TYPE(val) == T_NIL) {
429     return 0;
430   }
431 
432   if (is_map_field(f)) {
433     VALUE map;
434 
435     if (TYPE(val) != T_HASH) {
436       rb_raise(rb_eArgError,
437                "Expected Hash object as initializer value for map field '%s' (given %s).",
438                name, rb_class2name(CLASS_OF(val)));
439     }
440     map = layout_get(self->descriptor->layout, Message_data(self), f);
441     Map_merge_into_self(map, val);
442   } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
443     VALUE ary;
444     int i;
445 
446     if (TYPE(val) != T_ARRAY) {
447       rb_raise(rb_eArgError,
448                "Expected array as initializer value for repeated field '%s' (given %s).",
449                name, rb_class2name(CLASS_OF(val)));
450     }
451     ary = layout_get(self->descriptor->layout, Message_data(self), f);
452     for (i = 0; i < RARRAY_LEN(val); i++) {
453       VALUE entry = rb_ary_entry(val, i);
454       if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
455         entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
456       }
457 
458       RepeatedField_push(ary, entry);
459     }
460   } else {
461     if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
462       val = create_submsg_from_hash(self->descriptor->layout, f, val);
463     }
464 
465     layout_set(self->descriptor->layout, Message_data(self), f, val);
466   }
467   return 0;
468 }
469 
470 /*
471  * call-seq:
472  *     Message.new(kwargs) => new_message
473  *
474  * Creates a new instance of the given message class. Keyword arguments may be
475  * provided with keywords corresponding to field names.
476  *
477  * Note that no literal Message class exists. Only concrete classes per message
478  * type exist, as provided by the #msgclass method on Descriptors after they
479  * have been added to a pool. The method definitions described here on the
480  * Message class are provided on each concrete message class.
481  */
Message_initialize(int argc,VALUE * argv,VALUE _self)482 VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
483   MessageHeader* self;
484   VALUE hash_args;
485   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
486 
487   layout_init(self->descriptor->layout, Message_data(self));
488 
489   if (argc == 0) {
490     return Qnil;
491   }
492   if (argc != 1) {
493     rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
494   }
495   hash_args = argv[0];
496   if (TYPE(hash_args) != T_HASH) {
497     rb_raise(rb_eArgError, "Expected hash arguments.");
498   }
499 
500   rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
501   return Qnil;
502 }
503 
504 /*
505  * call-seq:
506  *     Message.dup => new_message
507  *
508  * Performs a shallow copy of this message and returns the new copy.
509  */
Message_dup(VALUE _self)510 VALUE Message_dup(VALUE _self) {
511   MessageHeader* self;
512   VALUE new_msg;
513   MessageHeader* new_msg_self;
514   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
515 
516   new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
517   TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
518 
519   layout_dup(self->descriptor->layout,
520              Message_data(new_msg_self),
521              Message_data(self));
522 
523   return new_msg;
524 }
525 
526 // Internal only; used by Google::Protobuf.deep_copy.
Message_deep_copy(VALUE _self)527 VALUE Message_deep_copy(VALUE _self) {
528   MessageHeader* self;
529   MessageHeader* new_msg_self;
530   VALUE new_msg;
531   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
532 
533   new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
534   TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
535 
536   layout_deep_copy(self->descriptor->layout,
537                    Message_data(new_msg_self),
538                    Message_data(self));
539 
540   return new_msg;
541 }
542 
543 /*
544  * call-seq:
545  *     Message.==(other) => boolean
546  *
547  * Performs a deep comparison of this message with another. Messages are equal
548  * if they have the same type and if each field is equal according to the :==
549  * method's semantics (a more efficient comparison may actually be done if the
550  * field is of a primitive type).
551  */
Message_eq(VALUE _self,VALUE _other)552 VALUE Message_eq(VALUE _self, VALUE _other) {
553   MessageHeader* self;
554   MessageHeader* other;
555   if (TYPE(_self) != TYPE(_other)) {
556     return Qfalse;
557   }
558   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
559   TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
560 
561   if (self->descriptor != other->descriptor) {
562     return Qfalse;
563   }
564 
565   return layout_eq(self->descriptor->layout,
566                    Message_data(self),
567                    Message_data(other));
568 }
569 
570 /*
571  * call-seq:
572  *     Message.hash => hash_value
573  *
574  * Returns a hash value that represents this message's field values.
575  */
Message_hash(VALUE _self)576 VALUE Message_hash(VALUE _self) {
577   MessageHeader* self;
578   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
579 
580   return layout_hash(self->descriptor->layout, Message_data(self));
581 }
582 
583 /*
584  * call-seq:
585  *     Message.inspect => string
586  *
587  * Returns a human-readable string representing this message. It will be
588  * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
589  * field's value is represented according to its own #inspect method.
590  */
Message_inspect(VALUE _self)591 VALUE Message_inspect(VALUE _self) {
592   MessageHeader* self;
593   VALUE str;
594   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
595 
596   str = rb_str_new2("<");
597   str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
598   str = rb_str_cat2(str, ": ");
599   str = rb_str_append(str, layout_inspect(
600       self->descriptor->layout, Message_data(self)));
601   str = rb_str_cat2(str, ">");
602   return str;
603 }
604 
605 /*
606  * call-seq:
607  *     Message.to_h => {}
608  *
609  * Returns the message as a Ruby Hash object, with keys as symbols.
610  */
Message_to_h(VALUE _self)611 VALUE Message_to_h(VALUE _self) {
612   MessageHeader* self;
613   VALUE hash = rb_hash_new();
614   upb_msg_field_iter it;
615   bool is_proto2;
616   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
617 
618   // We currently have a few behaviors that are specific to proto2.
619   // This is unfortunate, we should key behaviors off field attributes (like
620   // whether a field has presence), not proto2 vs. proto3. We should see if we
621   // can change this without breaking users.
622   is_proto2 =
623       upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2;
624 
625   for (upb_msg_field_begin(&it, self->descriptor->msgdef);
626        !upb_msg_field_done(&it);
627        upb_msg_field_next(&it)) {
628     const upb_fielddef* field = upb_msg_iter_field(&it);
629     VALUE msg_value;
630     VALUE msg_key;
631 
632     // Do not include fields that are not present (oneof or optional fields).
633     if (is_proto2 && upb_fielddef_haspresence(field) &&
634         !layout_has(self->descriptor->layout, Message_data(self), field)) {
635       continue;
636     }
637 
638     msg_value = layout_get(self->descriptor->layout, Message_data(self), field);
639     msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
640     if (is_map_field(field)) {
641       msg_value = Map_to_h(msg_value);
642     } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
643       msg_value = RepeatedField_to_ary(msg_value);
644       if (is_proto2 && RARRAY_LEN(msg_value) == 0) {
645         continue;
646       }
647 
648       if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
649         int i;
650         for (i = 0; i < RARRAY_LEN(msg_value); i++) {
651           VALUE elem = rb_ary_entry(msg_value, i);
652           rb_ary_store(msg_value, i, Message_to_h(elem));
653         }
654       }
655 
656     } else if (msg_value != Qnil &&
657                upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
658       msg_value = Message_to_h(msg_value);
659     }
660     rb_hash_aset(hash, msg_key, msg_value);
661   }
662   return hash;
663 }
664 
665 
666 
667 /*
668  * call-seq:
669  *     Message.[](index) => value
670  *
671  * Accesses a field's value by field name. The provided field name should be a
672  * string.
673  */
Message_index(VALUE _self,VALUE field_name)674 VALUE Message_index(VALUE _self, VALUE field_name) {
675   MessageHeader* self;
676   const upb_fielddef* field;
677   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
678   Check_Type(field_name, T_STRING);
679   field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
680   if (field == NULL) {
681     return Qnil;
682   }
683   return layout_get(self->descriptor->layout, Message_data(self), field);
684 }
685 
686 /*
687  * call-seq:
688  *     Message.[]=(index, value)
689  *
690  * Sets a field's value by field name. The provided field name should be a
691  * string.
692  */
Message_index_set(VALUE _self,VALUE field_name,VALUE value)693 VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
694   MessageHeader* self;
695   const upb_fielddef* field;
696   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
697   Check_Type(field_name, T_STRING);
698   field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
699   if (field == NULL) {
700     rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
701   }
702   layout_set(self->descriptor->layout, Message_data(self), field, value);
703   return Qnil;
704 }
705 
706 /*
707  * call-seq:
708  *     Message.descriptor => descriptor
709  *
710  * Class method that returns the Descriptor instance corresponding to this
711  * message class's type.
712  */
Message_descriptor(VALUE klass)713 VALUE Message_descriptor(VALUE klass) {
714   return rb_ivar_get(klass, descriptor_instancevar_interned);
715 }
716 
build_class_from_descriptor(VALUE descriptor)717 VALUE build_class_from_descriptor(VALUE descriptor) {
718   Descriptor* desc = ruby_to_Descriptor(descriptor);
719   const char *name;
720   VALUE klass;
721 
722   name = upb_msgdef_fullname(desc->msgdef);
723   if (name == NULL) {
724     rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
725   }
726 
727   klass = rb_define_class_id(
728       // Docs say this parameter is ignored. User will assign return value to
729       // their own toplevel constant class name.
730       rb_intern("Message"),
731       rb_cObject);
732   rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
733   rb_define_alloc_func(klass, Message_alloc);
734   rb_require("google/protobuf/message_exts");
735   rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
736   rb_extend_object(
737       klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
738 
739   rb_define_method(klass, "method_missing",
740                    Message_method_missing, -1);
741   rb_define_method(klass, "respond_to_missing?",
742                    Message_respond_to_missing, -1);
743   rb_define_method(klass, "initialize", Message_initialize, -1);
744   rb_define_method(klass, "dup", Message_dup, 0);
745   // Also define #clone so that we don't inherit Object#clone.
746   rb_define_method(klass, "clone", Message_dup, 0);
747   rb_define_method(klass, "==", Message_eq, 1);
748   rb_define_method(klass, "eql?", Message_eq, 1);
749   rb_define_method(klass, "hash", Message_hash, 0);
750   rb_define_method(klass, "to_h", Message_to_h, 0);
751   rb_define_method(klass, "inspect", Message_inspect, 0);
752   rb_define_method(klass, "to_s", Message_inspect, 0);
753   rb_define_method(klass, "[]", Message_index, 1);
754   rb_define_method(klass, "[]=", Message_index_set, 2);
755   rb_define_singleton_method(klass, "decode", Message_decode, 1);
756   rb_define_singleton_method(klass, "encode", Message_encode, 1);
757   rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
758   rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
759   rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
760 
761   return klass;
762 }
763 
764 /*
765  * call-seq:
766  *     Enum.lookup(number) => name
767  *
768  * This module method, provided on each generated enum module, looks up an enum
769  * value by number and returns its name as a Ruby symbol, or nil if not found.
770  */
enum_lookup(VALUE self,VALUE number)771 VALUE enum_lookup(VALUE self, VALUE number) {
772   int32_t num = NUM2INT(number);
773   VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
774   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
775 
776   const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
777   if (name == NULL) {
778     return Qnil;
779   } else {
780     return ID2SYM(rb_intern(name));
781   }
782 }
783 
784 /*
785  * call-seq:
786  *     Enum.resolve(name) => number
787  *
788  * This module method, provided on each generated enum module, looks up an enum
789  * value by name (as a Ruby symbol) and returns its name, or nil if not found.
790  */
enum_resolve(VALUE self,VALUE sym)791 VALUE enum_resolve(VALUE self, VALUE sym) {
792   const char* name = rb_id2name(SYM2ID(sym));
793   VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
794   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
795 
796   int32_t num = 0;
797   bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
798   if (!found) {
799     return Qnil;
800   } else {
801     return INT2NUM(num);
802   }
803 }
804 
805 /*
806  * call-seq:
807  *     Enum.descriptor
808  *
809  * This module method, provided on each generated enum module, returns the
810  * EnumDescriptor corresponding to this enum type.
811  */
enum_descriptor(VALUE self)812 VALUE enum_descriptor(VALUE self) {
813   return rb_ivar_get(self, descriptor_instancevar_interned);
814 }
815 
build_module_from_enumdesc(VALUE _enumdesc)816 VALUE build_module_from_enumdesc(VALUE _enumdesc) {
817   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
818   VALUE mod = rb_define_module_id(
819       rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
820 
821   upb_enum_iter it;
822   for (upb_enum_begin(&it, enumdesc->enumdef);
823        !upb_enum_done(&it);
824        upb_enum_next(&it)) {
825     const char* name = upb_enum_iter_name(&it);
826     int32_t value = upb_enum_iter_number(&it);
827     if (name[0] < 'A' || name[0] > 'Z') {
828       rb_warn("Enum value '%s' does not start with an uppercase letter "
829               "as is required for Ruby constants.",
830               name);
831     }
832     rb_define_const(mod, name, INT2NUM(value));
833   }
834 
835   rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
836   rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
837   rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
838   rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc);
839 
840   return mod;
841 }
842 
843 /*
844  * call-seq:
845  *     Google::Protobuf.deep_copy(obj) => copy_of_obj
846  *
847  * Performs a deep copy of a RepeatedField instance, a Map instance, or a
848  * message object, recursively copying its members.
849  */
Google_Protobuf_deep_copy(VALUE self,VALUE obj)850 VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
851   VALUE klass = CLASS_OF(obj);
852   if (klass == cRepeatedField) {
853     return RepeatedField_deep_copy(obj);
854   } else if (klass == cMap) {
855     return Map_deep_copy(obj);
856   } else {
857     return Message_deep_copy(obj);
858   }
859 }
860