• 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 = (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 
75   msg->unknown_fields = NULL;
76 
77   layout_init(desc->layout, Message_data(msg));
78 
79   return ret;
80 }
81 
which_oneof_field(MessageHeader * self,const upb_oneofdef * o)82 static const upb_fielddef* 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 NULL;
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 NULL;
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 f;
114 }
115 
116 enum {
117   METHOD_UNKNOWN = 0,
118   METHOD_GETTER = 1,
119   METHOD_SETTER = 2,
120   METHOD_CLEAR = 3,
121   METHOD_PRESENCE = 4,
122   METHOD_ENUM_GETTER = 5,
123   METHOD_WRAPPER_GETTER = 6,
124   METHOD_WRAPPER_SETTER = 7
125 };
126 
127 // Check if the field is a well known wrapper type
is_wrapper_type_field(const upb_fielddef * field)128 static bool is_wrapper_type_field(const upb_fielddef* field) {
129   char* field_type_name = rb_class2name(field_type_class(field));
130 
131   return strcmp(field_type_name, "Google::Protobuf::DoubleValue") == 0 ||
132          strcmp(field_type_name, "Google::Protobuf::FloatValue") == 0 ||
133          strcmp(field_type_name, "Google::Protobuf::Int32Value") == 0 ||
134          strcmp(field_type_name, "Google::Protobuf::Int64Value") == 0 ||
135          strcmp(field_type_name, "Google::Protobuf::UInt32Value") == 0 ||
136          strcmp(field_type_name, "Google::Protobuf::UInt64Value") == 0 ||
137          strcmp(field_type_name, "Google::Protobuf::BoolValue") == 0 ||
138          strcmp(field_type_name, "Google::Protobuf::StringValue") == 0 ||
139          strcmp(field_type_name, "Google::Protobuf::BytesValue") == 0;
140 }
141 
142 // Get a new Ruby wrapper type and set the initial value
ruby_wrapper_type(const upb_fielddef * field,const VALUE * value)143 static VALUE ruby_wrapper_type(const upb_fielddef* field, const VALUE* value) {
144   if (is_wrapper_type_field(field) && value != Qnil) {
145     VALUE hash = rb_hash_new();
146     rb_hash_aset(hash, rb_str_new2("value"), value);
147     VALUE args[1] = { hash };
148     return rb_class_new_instance(1, args, field_type_class(field));
149   }
150   return Qnil;
151 }
152 
extract_method_call(VALUE method_name,MessageHeader * self,const upb_fielddef ** f,const upb_oneofdef ** o)153 static int extract_method_call(VALUE method_name, MessageHeader* self,
154 			       const upb_fielddef **f, const upb_oneofdef **o) {
155   Check_Type(method_name, T_SYMBOL);
156 
157   VALUE method_str = rb_id2str(SYM2ID(method_name));
158   char* name = RSTRING_PTR(method_str);
159   size_t name_len = RSTRING_LEN(method_str);
160   int accessor_type;
161   const upb_oneofdef* test_o;
162   const upb_fielddef* test_f;
163 
164   if (name[name_len - 1] == '=') {
165     accessor_type = METHOD_SETTER;
166     name_len--;
167     // We want to ensure if the proto has something named clear_foo or has_foo?,
168     // we don't strip the prefix.
169   } else if (strncmp("clear_", name, 6) == 0 &&
170              !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
171 				    &test_f, &test_o)) {
172     accessor_type = METHOD_CLEAR;
173     name = name + 6;
174     name_len = name_len - 6;
175   } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
176              !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
177 				    &test_f, &test_o)) {
178     accessor_type = METHOD_PRESENCE;
179     name = name + 4;
180     name_len = name_len - 5;
181   } else {
182     accessor_type = METHOD_GETTER;
183   }
184 
185   bool has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
186 			                                   &test_f, &test_o);
187 
188   // Look for wrapper type accessor of the form <field_name>_as_value
189   if (!has_field &&
190       (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
191       name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
192     // Find the field name
193     char wrapper_field_name[name_len - 8];
194     strncpy(wrapper_field_name, name, name_len - 9);
195     wrapper_field_name[name_len - 7] = '\0';
196 
197     // Check if field exists and is a wrapper type
198     const upb_oneofdef* test_o_wrapper;
199     const upb_fielddef* test_f_wrapper;
200     if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name, name_len - 9,
201 			                        &test_f_wrapper, &test_o_wrapper) &&
202         upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
203         is_wrapper_type_field(test_f_wrapper)) {
204       // It does exist!
205       has_field = true;
206       if (accessor_type == METHOD_SETTER) {
207         accessor_type = METHOD_WRAPPER_SETTER;
208       } else {
209         accessor_type = METHOD_WRAPPER_GETTER;
210       }
211       test_o = test_o_wrapper;
212       test_f = test_f_wrapper;
213     }
214   }
215 
216   // Look for enum accessor of the form <enum_name>_const
217   if (!has_field && accessor_type == METHOD_GETTER &&
218       name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
219 
220     // Find enum field name
221     char enum_name[name_len - 5];
222     strncpy(enum_name, name, name_len - 6);
223     enum_name[name_len - 4] = '\0';
224 
225     // Check if enum field exists
226     const upb_oneofdef* test_o_enum;
227     const upb_fielddef* test_f_enum;
228     if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
229 			                        &test_f_enum, &test_o_enum) &&
230         upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
231       // It does exist!
232       has_field = true;
233       accessor_type = METHOD_ENUM_GETTER;
234       test_o = test_o_enum;
235       test_f = test_f_enum;
236     }
237   }
238 
239   // Verify the name corresponds to a oneof or field in this message.
240   if (!has_field) {
241     return METHOD_UNKNOWN;
242   }
243 
244   // Method calls like 'has_foo?' are not allowed if field "foo" does not have
245   // a hasbit (e.g. repeated fields or non-message type fields for proto3
246   // syntax).
247   if (accessor_type == METHOD_PRESENCE && test_f != NULL &&
248       !upb_fielddef_haspresence(test_f)) {
249     return METHOD_UNKNOWN;
250   }
251 
252   *o = test_o;
253   *f = test_f;
254   return accessor_type;
255 }
256 
257 /*
258  * call-seq:
259  *     Message.method_missing(*args)
260  *
261  * Provides accessors and setters and methods to clear and check for presence of
262  * message fields according to their field names.
263  *
264  * For any field whose name does not conflict with a built-in method, an
265  * accessor is provided with the same name as the field, and a setter is
266  * provided with the name of the field plus the '=' suffix. Thus, given a
267  * message instance 'msg' with field 'foo', the following code is valid:
268  *
269  *     msg.foo = 42
270  *     puts msg.foo
271  *
272  * This method also provides read-only accessors for oneofs. If a oneof exists
273  * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
274  * the name of the field in that oneof that is currently set, or nil if none.
275  *
276  * It also provides methods of the form 'clear_fieldname' to clear the value
277  * of the field 'fieldname'. For basic data types, this will set the default
278  * value of the field.
279  *
280  * Additionally, it provides methods of the form 'has_fieldname?', which returns
281  * true if the field 'fieldname' is set in the message object, else false. For
282  * 'proto3' syntax, calling this for a basic type field will result in an error.
283  */
Message_method_missing(int argc,VALUE * argv,VALUE _self)284 VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
285   MessageHeader* self;
286   const upb_oneofdef* o;
287   const upb_fielddef* f;
288 
289   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
290   if (argc < 1) {
291     rb_raise(rb_eArgError, "Expected method name as first argument.");
292   }
293 
294   int accessor_type = extract_method_call(argv[0], self, &f, &o);
295   if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
296     return rb_call_super(argc, argv);
297   } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
298     if (argc != 2) {
299       rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
300     }
301     rb_check_frozen(_self);
302   } else if (argc != 1) {
303     rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
304   }
305 
306   // Return which of the oneof fields are set
307   if (o != NULL) {
308     if (accessor_type == METHOD_SETTER) {
309       rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
310     }
311 
312     const upb_fielddef* oneof_field = which_oneof_field(self, o);
313     if (accessor_type == METHOD_PRESENCE) {
314       return oneof_field == NULL ? Qfalse : Qtrue;
315     } else if (accessor_type == METHOD_CLEAR) {
316       if (oneof_field != NULL) {
317         layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
318       }
319       return Qnil;
320     } else {
321       // METHOD_ACCESSOR
322       return oneof_field == NULL ? Qnil :
323         ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
324     }
325   // Otherwise we're operating on a single proto field
326   } else if (accessor_type == METHOD_SETTER) {
327     layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
328     return Qnil;
329   } else if (accessor_type == METHOD_CLEAR) {
330     layout_clear(self->descriptor->layout, Message_data(self), f);
331     return Qnil;
332   } else if (accessor_type == METHOD_PRESENCE) {
333     return layout_has(self->descriptor->layout, Message_data(self), f);
334   } else if (accessor_type == METHOD_WRAPPER_GETTER) {
335     VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
336     if (value != Qnil) {
337       value = rb_funcall(value, rb_intern("value"), 0);
338     }
339     return value;
340   } else if (accessor_type == METHOD_WRAPPER_SETTER) {
341     VALUE wrapper = ruby_wrapper_type(f, argv[1]);
342     layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
343     return Qnil;
344   } else if (accessor_type == METHOD_ENUM_GETTER) {
345     VALUE enum_type = field_type_class(f);
346     VALUE method = rb_intern("const_get");
347     VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
348 
349     // Map repeated fields to a new type with ints
350     if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
351       int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
352       VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
353       VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
354       for (int i = 0; i < array_size; i++) {
355         VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
356                                  rb_intern("at"), 1, INT2NUM(i)));
357         rb_funcall(array, rb_intern("push"), 1, entry);
358       }
359       return array;
360     }
361     // Convert the value for singular fields
362     return rb_funcall(enum_type, method, 1, raw_value);
363   } else {
364     return layout_get(self->descriptor->layout, Message_data(self), f);
365   }
366 }
367 
368 
Message_respond_to_missing(int argc,VALUE * argv,VALUE _self)369 VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
370   MessageHeader* self;
371   const upb_oneofdef* o;
372   const upb_fielddef* f;
373 
374   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
375   if (argc < 1) {
376     rb_raise(rb_eArgError, "Expected method name as first argument.");
377   }
378 
379   int accessor_type = extract_method_call(argv[0], self, &f, &o);
380   if (accessor_type == METHOD_UNKNOWN) {
381     return rb_call_super(argc, argv);
382   } else if (o != NULL) {
383     return accessor_type == METHOD_SETTER ? Qfalse : Qtrue;
384   } else {
385     return Qtrue;
386   }
387 }
388 
create_submsg_from_hash(const upb_fielddef * f,VALUE hash)389 VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
390   const upb_def *d = upb_fielddef_subdef(f);
391   assert(d != NULL);
392 
393   VALUE descriptor = get_def_obj(d);
394   VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
395 
396   VALUE args[1] = { hash };
397   return rb_class_new_instance(1, args, msgclass);
398 }
399 
Message_initialize_kwarg(VALUE key,VALUE val,VALUE _self)400 int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
401   MessageHeader* self;
402   char *name;
403   const upb_fielddef* f;
404   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
405 
406   if (TYPE(key) == T_STRING) {
407     name = RSTRING_PTR(key);
408   } else if (TYPE(key) == T_SYMBOL) {
409     name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
410   } else {
411     rb_raise(rb_eArgError,
412              "Expected string or symbols as hash keys when initializing proto from hash.");
413   }
414 
415   f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
416   if (f == NULL) {
417     rb_raise(rb_eArgError,
418              "Unknown field name '%s' in initialization map entry.", name);
419   }
420 
421   if (TYPE(val) == T_NIL) {
422     return 0;
423   }
424 
425   if (is_map_field(f)) {
426     VALUE map;
427 
428     if (TYPE(val) != T_HASH) {
429       rb_raise(rb_eArgError,
430                "Expected Hash object as initializer value for map field '%s' (given %s).",
431                name, rb_class2name(CLASS_OF(val)));
432     }
433     map = layout_get(self->descriptor->layout, Message_data(self), f);
434     Map_merge_into_self(map, val);
435   } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
436     VALUE ary;
437 
438     if (TYPE(val) != T_ARRAY) {
439       rb_raise(rb_eArgError,
440                "Expected array as initializer value for repeated field '%s' (given %s).",
441                name, rb_class2name(CLASS_OF(val)));
442     }
443     ary = layout_get(self->descriptor->layout, Message_data(self), f);
444     for (int i = 0; i < RARRAY_LEN(val); i++) {
445       VALUE entry = rb_ary_entry(val, i);
446       if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
447         entry = create_submsg_from_hash(f, entry);
448       }
449 
450       RepeatedField_push(ary, entry);
451     }
452   } else {
453     if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
454       val = create_submsg_from_hash(f, val);
455     }
456 
457     layout_set(self->descriptor->layout, Message_data(self), f, val);
458   }
459   return 0;
460 }
461 
462 /*
463  * call-seq:
464  *     Message.new(kwargs) => new_message
465  *
466  * Creates a new instance of the given message class. Keyword arguments may be
467  * provided with keywords corresponding to field names.
468  *
469  * Note that no literal Message class exists. Only concrete classes per message
470  * type exist, as provided by the #msgclass method on Descriptors after they
471  * have been added to a pool. The method definitions described here on the
472  * Message class are provided on each concrete message class.
473  */
Message_initialize(int argc,VALUE * argv,VALUE _self)474 VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
475   VALUE hash_args;
476 
477   if (argc == 0) {
478     return Qnil;
479   }
480   if (argc != 1) {
481     rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
482   }
483   hash_args = argv[0];
484   if (TYPE(hash_args) != T_HASH) {
485     rb_raise(rb_eArgError, "Expected hash arguments.");
486   }
487 
488   rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
489   return Qnil;
490 }
491 
492 /*
493  * call-seq:
494  *     Message.dup => new_message
495  *
496  * Performs a shallow copy of this message and returns the new copy.
497  */
Message_dup(VALUE _self)498 VALUE Message_dup(VALUE _self) {
499   MessageHeader* self;
500   VALUE new_msg;
501   MessageHeader* new_msg_self;
502   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
503 
504   new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
505   TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
506 
507   layout_dup(self->descriptor->layout,
508              Message_data(new_msg_self),
509              Message_data(self));
510 
511   return new_msg;
512 }
513 
514 // Internal only; used by Google::Protobuf.deep_copy.
Message_deep_copy(VALUE _self)515 VALUE Message_deep_copy(VALUE _self) {
516   MessageHeader* self;
517   MessageHeader* new_msg_self;
518   VALUE new_msg;
519   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
520 
521   new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
522   TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
523 
524   layout_deep_copy(self->descriptor->layout,
525                    Message_data(new_msg_self),
526                    Message_data(self));
527 
528   return new_msg;
529 }
530 
531 /*
532  * call-seq:
533  *     Message.==(other) => boolean
534  *
535  * Performs a deep comparison of this message with another. Messages are equal
536  * if they have the same type and if each field is equal according to the :==
537  * method's semantics (a more efficient comparison may actually be done if the
538  * field is of a primitive type).
539  */
Message_eq(VALUE _self,VALUE _other)540 VALUE Message_eq(VALUE _self, VALUE _other) {
541   MessageHeader* self;
542   MessageHeader* other;
543   if (TYPE(_self) != TYPE(_other)) {
544     return Qfalse;
545   }
546   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
547   TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
548 
549   if (self->descriptor != other->descriptor) {
550     return Qfalse;
551   }
552 
553   return layout_eq(self->descriptor->layout,
554                    Message_data(self),
555                    Message_data(other));
556 }
557 
558 /*
559  * call-seq:
560  *     Message.hash => hash_value
561  *
562  * Returns a hash value that represents this message's field values.
563  */
Message_hash(VALUE _self)564 VALUE Message_hash(VALUE _self) {
565   MessageHeader* self;
566   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
567 
568   return layout_hash(self->descriptor->layout, Message_data(self));
569 }
570 
571 /*
572  * call-seq:
573  *     Message.inspect => string
574  *
575  * Returns a human-readable string representing this message. It will be
576  * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
577  * field's value is represented according to its own #inspect method.
578  */
Message_inspect(VALUE _self)579 VALUE Message_inspect(VALUE _self) {
580   MessageHeader* self;
581   VALUE str;
582   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
583 
584   str = rb_str_new2("<");
585   str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
586   str = rb_str_cat2(str, ": ");
587   str = rb_str_append(str, layout_inspect(
588       self->descriptor->layout, Message_data(self)));
589   str = rb_str_cat2(str, ">");
590   return str;
591 }
592 
593 /*
594  * call-seq:
595  *     Message.to_h => {}
596  *
597  * Returns the message as a Ruby Hash object, with keys as symbols.
598  */
Message_to_h(VALUE _self)599 VALUE Message_to_h(VALUE _self) {
600   MessageHeader* self;
601   VALUE hash;
602   upb_msg_field_iter it;
603   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
604 
605   hash = rb_hash_new();
606 
607   for (upb_msg_field_begin(&it, self->descriptor->msgdef);
608        !upb_msg_field_done(&it);
609        upb_msg_field_next(&it)) {
610     const upb_fielddef* field = upb_msg_iter_field(&it);
611 
612     // For proto2, do not include fields which are not set.
613     if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
614 	field_contains_hasbit(self->descriptor->layout, field) &&
615 	!layout_has(self->descriptor->layout, Message_data(self), field)) {
616       continue;
617     }
618 
619     VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
620                                  field);
621     VALUE msg_key   = ID2SYM(rb_intern(upb_fielddef_name(field)));
622     if (is_map_field(field)) {
623       msg_value = Map_to_h(msg_value);
624     } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
625       msg_value = RepeatedField_to_ary(msg_value);
626       if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
627           RARRAY_LEN(msg_value) == 0) {
628         continue;
629       }
630 
631       if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
632         for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
633           VALUE elem = rb_ary_entry(msg_value, i);
634           rb_ary_store(msg_value, i, Message_to_h(elem));
635         }
636       }
637 
638     } else if (msg_value != Qnil &&
639                upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
640       msg_value = Message_to_h(msg_value);
641     }
642     rb_hash_aset(hash, msg_key, msg_value);
643   }
644   return hash;
645 }
646 
647 
648 
649 /*
650  * call-seq:
651  *     Message.[](index) => value
652  *
653  * Accesses a field's value by field name. The provided field name should be a
654  * string.
655  */
Message_index(VALUE _self,VALUE field_name)656 VALUE Message_index(VALUE _self, VALUE field_name) {
657   MessageHeader* self;
658   const upb_fielddef* field;
659   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
660   Check_Type(field_name, T_STRING);
661   field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
662   if (field == NULL) {
663     return Qnil;
664   }
665   return layout_get(self->descriptor->layout, Message_data(self), field);
666 }
667 
668 /*
669  * call-seq:
670  *     Message.[]=(index, value)
671  *
672  * Sets a field's value by field name. The provided field name should be a
673  * string.
674  */
Message_index_set(VALUE _self,VALUE field_name,VALUE value)675 VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
676   MessageHeader* self;
677   const upb_fielddef* field;
678   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
679   Check_Type(field_name, T_STRING);
680   field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
681   if (field == NULL) {
682     rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
683   }
684   layout_set(self->descriptor->layout, Message_data(self), field, value);
685   return Qnil;
686 }
687 
688 /*
689  * call-seq:
690  *     Message.descriptor => descriptor
691  *
692  * Class method that returns the Descriptor instance corresponding to this
693  * message class's type.
694  */
Message_descriptor(VALUE klass)695 VALUE Message_descriptor(VALUE klass) {
696   return rb_ivar_get(klass, descriptor_instancevar_interned);
697 }
698 
build_class_from_descriptor(Descriptor * desc)699 VALUE build_class_from_descriptor(Descriptor* desc) {
700   const char *name;
701   VALUE klass;
702 
703   if (desc->layout == NULL) {
704     desc->layout = create_layout(desc->msgdef);
705   }
706   if (desc->fill_method == NULL) {
707     desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
708   }
709 
710   name = upb_msgdef_fullname(desc->msgdef);
711   if (name == NULL) {
712     rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
713   }
714 
715   klass = rb_define_class_id(
716       // Docs say this parameter is ignored. User will assign return value to
717       // their own toplevel constant class name.
718       rb_intern("Message"),
719       rb_cObject);
720   rb_ivar_set(klass, descriptor_instancevar_interned,
721               get_def_obj(desc->msgdef));
722   rb_define_alloc_func(klass, Message_alloc);
723   rb_require("google/protobuf/message_exts");
724   rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
725   rb_extend_object(
726       klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
727 
728   rb_define_method(klass, "method_missing",
729                    Message_method_missing, -1);
730   rb_define_method(klass, "respond_to_missing?",
731                    Message_respond_to_missing, -1);
732   rb_define_method(klass, "initialize", Message_initialize, -1);
733   rb_define_method(klass, "dup", Message_dup, 0);
734   // Also define #clone so that we don't inherit Object#clone.
735   rb_define_method(klass, "clone", Message_dup, 0);
736   rb_define_method(klass, "==", Message_eq, 1);
737   rb_define_method(klass, "eql?", Message_eq, 1);
738   rb_define_method(klass, "hash", Message_hash, 0);
739   rb_define_method(klass, "to_h", Message_to_h, 0);
740   rb_define_method(klass, "inspect", Message_inspect, 0);
741   rb_define_method(klass, "to_s", Message_inspect, 0);
742   rb_define_method(klass, "[]", Message_index, 1);
743   rb_define_method(klass, "[]=", Message_index_set, 2);
744   rb_define_singleton_method(klass, "decode", Message_decode, 1);
745   rb_define_singleton_method(klass, "encode", Message_encode, 1);
746   rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
747   rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
748   rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
749 
750   return klass;
751 }
752 
753 /*
754  * call-seq:
755  *     Enum.lookup(number) => name
756  *
757  * This module method, provided on each generated enum module, looks up an enum
758  * value by number and returns its name as a Ruby symbol, or nil if not found.
759  */
enum_lookup(VALUE self,VALUE number)760 VALUE enum_lookup(VALUE self, VALUE number) {
761   int32_t num = NUM2INT(number);
762   VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
763   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
764 
765   const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
766   if (name == NULL) {
767     return Qnil;
768   } else {
769     return ID2SYM(rb_intern(name));
770   }
771 }
772 
773 /*
774  * call-seq:
775  *     Enum.resolve(name) => number
776  *
777  * This module method, provided on each generated enum module, looks up an enum
778  * value by name (as a Ruby symbol) and returns its name, or nil if not found.
779  */
enum_resolve(VALUE self,VALUE sym)780 VALUE enum_resolve(VALUE self, VALUE sym) {
781   const char* name = rb_id2name(SYM2ID(sym));
782   VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
783   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
784 
785   int32_t num = 0;
786   bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
787   if (!found) {
788     return Qnil;
789   } else {
790     return INT2NUM(num);
791   }
792 }
793 
794 /*
795  * call-seq:
796  *     Enum.descriptor
797  *
798  * This module method, provided on each generated enum module, returns the
799  * EnumDescriptor corresponding to this enum type.
800  */
enum_descriptor(VALUE self)801 VALUE enum_descriptor(VALUE self) {
802   return rb_ivar_get(self, descriptor_instancevar_interned);
803 }
804 
build_module_from_enumdesc(EnumDescriptor * enumdesc)805 VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
806   VALUE mod = rb_define_module_id(
807       rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
808 
809   upb_enum_iter it;
810   for (upb_enum_begin(&it, enumdesc->enumdef);
811        !upb_enum_done(&it);
812        upb_enum_next(&it)) {
813     const char* name = upb_enum_iter_name(&it);
814     int32_t value = upb_enum_iter_number(&it);
815     if (name[0] < 'A' || name[0] > 'Z') {
816       rb_warn("Enum value '%s' does not start with an uppercase letter "
817               "as is required for Ruby constants.",
818               name);
819     }
820     rb_define_const(mod, name, INT2NUM(value));
821   }
822 
823   rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
824   rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
825   rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
826   rb_ivar_set(mod, descriptor_instancevar_interned,
827               get_def_obj(enumdesc->enumdef));
828 
829   return mod;
830 }
831 
832 /*
833  * call-seq:
834  *     Google::Protobuf.deep_copy(obj) => copy_of_obj
835  *
836  * Performs a deep copy of a RepeatedField instance, a Map instance, or a
837  * message object, recursively copying its members.
838  */
Google_Protobuf_deep_copy(VALUE self,VALUE obj)839 VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
840   VALUE klass = CLASS_OF(obj);
841   if (klass == cRepeatedField) {
842     return RepeatedField_deep_copy(obj);
843   } else if (klass == cMap) {
844     return Map_deep_copy(obj);
845   } else {
846     return Message_deep_copy(obj);
847   }
848 }
849