예제 #1
0
static void check_map_field_type(VALUE val, const upb_fielddef* field) {
    assert(is_map_field(field));
    const upb_fielddef* key_field = map_field_key(field);
    const upb_fielddef* value_field = map_field_value(field);

    if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
            RTYPEDDATA_TYPE(val) != &Map_type) {
        rb_raise(rb_eTypeError, "Expected Map instance");
    }

    Map* self = ruby_to_Map(val);
    if (self->key_type != upb_fielddef_type(key_field)) {
        rb_raise(rb_eTypeError, "Map key type does not match field's key type");
    }
    if (self->value_type != upb_fielddef_type(value_field)) {
        rb_raise(rb_eTypeError, "Map value type does not match field's value type");
    }
    if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
            upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
        if (self->value_type_class !=
                get_def_obj(upb_fielddef_subdef(value_field))) {
            rb_raise(rb_eTypeError,
                     "Map value type has wrong message/enum class");
        }
    }
}
예제 #2
0
void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
  upb_msg_field_iter it;
  for (upb_msg_field_begin(&it, layout->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);

    void* to_memory = slot_memory(layout, to, field);
    uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
    void* from_memory = slot_memory(layout, from, field);
    uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);

    if (upb_fielddef_containingoneof(field)) {
      if (*from_oneof_case == upb_fielddef_number(field)) {
        *to_oneof_case = *from_oneof_case;
        native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
      }
    } else if (is_map_field(field)) {
      DEREF(to_memory, VALUE) =
          Map_deep_copy(DEREF(from_memory, VALUE));
    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
      DEREF(to_memory, VALUE) =
          RepeatedField_deep_copy(DEREF(from_memory, VALUE));
    } else {
      if (field_contains_hasbit(layout, field)) {
        if (!slot_is_hasbit_set(layout, from, field)) continue;
        slot_set_hasbit(layout, to, field);
      }

      native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
    }
  }
}
예제 #3
0
void layout_clear(MessageLayout* layout,
                 const void* storage,
                 const upb_fielddef* field) {
  void* memory = slot_memory(layout, storage, field);
  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);

  if (field_contains_hasbit(layout, field)) {
    slot_clear_hasbit(layout, storage, field);
  }

  if (upb_fielddef_containingoneof(field)) {
    memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
    *oneof_case = ONEOF_CASE_NONE;
  } else if (is_map_field(field)) {
    VALUE map = Qnil;

    const upb_fielddef* key_field = map_field_key(field);
    const upb_fielddef* value_field = map_field_value(field);
    VALUE type_class = field_type_class(value_field);

    if (type_class != Qnil) {
      VALUE args[3] = {
        fieldtype_to_ruby(upb_fielddef_type(key_field)),
        fieldtype_to_ruby(upb_fielddef_type(value_field)),
        type_class,
      };
      map = rb_class_new_instance(3, args, cMap);
    } else {
      VALUE args[2] = {
        fieldtype_to_ruby(upb_fielddef_type(key_field)),
        fieldtype_to_ruby(upb_fielddef_type(value_field)),
      };
      map = rb_class_new_instance(2, args, cMap);
    }

    DEREF(memory, VALUE) = map;
  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
    VALUE ary = Qnil;

    VALUE type_class = field_type_class(field);

    if (type_class != Qnil) {
      VALUE args[2] = {
        fieldtype_to_ruby(upb_fielddef_type(field)),
        type_class,
      };
      ary = rb_class_new_instance(2, args, cRepeatedField);
    } else {
      VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
      ary = rb_class_new_instance(1, args, cRepeatedField);
    }

    DEREF(memory, VALUE) = ary;
  } else {
    native_slot_set(upb_fielddef_name(field),
                    upb_fielddef_type(field), field_type_class(field),
                    memory, layout_get_default(field));
  }
}
예제 #4
0
파일: message.c 프로젝트: hack0303/protobuf
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
  MessageHeader* self;
  char *name;
  const upb_fielddef* f;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  if (TYPE(key) == T_STRING) {
    name = RSTRING_PTR(key);
  } else if (TYPE(key) == T_SYMBOL) {
    name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
  } else {
    rb_raise(rb_eArgError,
             "Expected string or symbols as hash keys when initializing proto from hash.");
  }

  f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
  if (f == NULL) {
    rb_raise(rb_eArgError,
             "Unknown field name '%s' in initialization map entry.", name);
  }

  if (TYPE(val) == T_NIL) {
    return 0;
  }

  if (is_map_field(f)) {
    VALUE map;

    if (TYPE(val) != T_HASH) {
      rb_raise(rb_eArgError,
               "Expected Hash object as initializer value for map field '%s'.", name);
    }
    map = layout_get(self->descriptor->layout, Message_data(self), f);
    Map_merge_into_self(map, val);
  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
    VALUE ary;

    if (TYPE(val) != T_ARRAY) {
      rb_raise(rb_eArgError,
               "Expected array as initializer value for repeated field '%s'.", name);
    }
    ary = layout_get(self->descriptor->layout, Message_data(self), f);
    for (int i = 0; i < RARRAY_LEN(val); i++) {
      VALUE entry = rb_ary_entry(val, i);
      if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
        entry = create_submsg_from_hash(f, entry);
      }

      RepeatedField_push(ary, entry);
    }
  } else {
    if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
      val = create_submsg_from_hash(f, val);
    }

    layout_set(self->descriptor->layout, Message_data(self), f, val);
  }
  return 0;
}
예제 #5
0
void layout_init(MessageLayout* layout,
                 void* storage) {
    upb_msg_field_iter it;
    for (upb_msg_field_begin(&it, layout->msgdef);
            !upb_msg_field_done(&it);
            upb_msg_field_next(&it)) {
        const upb_fielddef* field = upb_msg_iter_field(&it);
        void* memory = slot_memory(layout, storage, field);
        uint32_t* oneof_case = slot_oneof_case(layout, storage, field);

        if (upb_fielddef_containingoneof(field)) {
            memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
            *oneof_case = ONEOF_CASE_NONE;
        } else if (is_map_field(field)) {
            VALUE map = Qnil;

            const upb_fielddef* key_field = map_field_key(field);
            const upb_fielddef* value_field = map_field_value(field);
            VALUE type_class = field_type_class(value_field);

            if (type_class != Qnil) {
                VALUE args[3] = {
                    fieldtype_to_ruby(upb_fielddef_type(key_field)),
                    fieldtype_to_ruby(upb_fielddef_type(value_field)),
                    type_class,
                };
                map = rb_class_new_instance(3, args, cMap);
            } else {
                VALUE args[2] = {
                    fieldtype_to_ruby(upb_fielddef_type(key_field)),
                    fieldtype_to_ruby(upb_fielddef_type(value_field)),
                };
                map = rb_class_new_instance(2, args, cMap);
            }

            DEREF(memory, VALUE) = map;
        } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
            VALUE ary = Qnil;

            VALUE type_class = field_type_class(field);

            if (type_class != Qnil) {
                VALUE args[2] = {
                    fieldtype_to_ruby(upb_fielddef_type(field)),
                    type_class,
                };
                ary = rb_class_new_instance(2, args, cRepeatedField);
            } else {
                VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
                ary = rb_class_new_instance(1, args, cRepeatedField);
            }

            DEREF(memory, VALUE) = ary;
        } else {
            native_slot_init(upb_fielddef_type(field), memory);
        }
    }
}
예제 #6
0
void layout_set(MessageLayout* layout,
                void* storage,
                const upb_fielddef* field,
                VALUE val) {
  void* memory = slot_memory(layout, storage, field);
  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);

  if (upb_fielddef_containingoneof(field)) {
    if (val == Qnil) {
      // Assigning nil to a oneof field clears the oneof completely.
      *oneof_case = ONEOF_CASE_NONE;
      memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
    } else {
      // The transition between field types for a single oneof (union) slot is
      // somewhat complex because we need to ensure that a GC triggered at any
      // point by a call into the Ruby VM sees a valid state for this field and
      // does not either go off into the weeds (following what it thinks is a
      // VALUE but is actually a different field type) or miss an object (seeing
      // what it thinks is a primitive field but is actually a VALUE for the new
      // field type).
      //
      // In order for the transition to be safe, the oneof case slot must be in
      // sync with the value slot whenever the Ruby VM has been called. Thus, we
      // use native_slot_set_value_and_case(), which ensures that both the value
      // and case number are altered atomically (w.r.t. the Ruby VM).
      native_slot_set_value_and_case(
          upb_fielddef_name(field),
          upb_fielddef_type(field), field_type_class(field),
          memory, val,
          oneof_case, upb_fielddef_number(field));
    }
  } else if (is_map_field(field)) {
    check_map_field_type(val, field);
    DEREF(memory, VALUE) = val;
  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
    check_repeated_field_type(val, field);
    DEREF(memory, VALUE) = val;
  } else {
    native_slot_set(upb_fielddef_name(field),
                    upb_fielddef_type(field), field_type_class(field),
                    memory, val);
  }

  if (layout->fields[upb_fielddef_index(field)].hasbit !=
      MESSAGE_FIELD_NO_HASBIT) {
    slot_set_hasbit(layout, storage, field);
  }
}
예제 #7
0
파일: message.c 프로젝트: hack0303/protobuf
/*
 * call-seq:
 *     Message.to_h => {}
 *
 * Returns the message as a Ruby Hash object, with keys as symbols.
 */
VALUE Message_to_h(VALUE _self) {
  MessageHeader* self;
  VALUE hash;
  upb_msg_field_iter it;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  hash = rb_hash_new();

  for (upb_msg_field_begin(&it, self->descriptor->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);

    // For proto2, do not include fields which are not set.
    if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
	field_contains_hasbit(self->descriptor->layout, field) &&
	!layout_has(self->descriptor->layout, Message_data(self), field)) {
      continue;
    }

    VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
                                 field);
    VALUE msg_key   = ID2SYM(rb_intern(upb_fielddef_name(field)));
    if (is_map_field(field)) {
      msg_value = Map_to_h(msg_value);
    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
      msg_value = RepeatedField_to_ary(msg_value);
      if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
          RARRAY_LEN(msg_value) == 0) {
        continue;
      }

      if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
        for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
          VALUE elem = rb_ary_entry(msg_value, i);
          rb_ary_store(msg_value, i, Message_to_h(elem));
        }
      }

    } else if (msg_value != Qnil &&
               upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
      msg_value = Message_to_h(msg_value);
    }
    rb_hash_aset(hash, msg_key, msg_value);
  }
  return hash;
}
예제 #8
0
파일: message.c 프로젝트: 1nf1corp/protobuf
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
  MessageHeader* self;
  VALUE method_str;
  char* name;
  const upb_fielddef* f;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  if (!SYMBOL_P(key)) {
    rb_raise(rb_eArgError,
             "Expected symbols as hash keys in initialization map.");
  }

  method_str = rb_id2str(SYM2ID(key));
  name = RSTRING_PTR(method_str);
  f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
  if (f == NULL) {
    rb_raise(rb_eArgError,
             "Unknown field name '%s' in initialization map entry.", name);
  }

  if (is_map_field(f)) {
    VALUE map;

    if (TYPE(val) != T_HASH) {
      rb_raise(rb_eArgError,
               "Expected Hash object as initializer value for map field '%s'.", name);
    }
    map = layout_get(self->descriptor->layout, Message_data(self), f);
    Map_merge_into_self(map, val);
  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
    VALUE ary;

    if (TYPE(val) != T_ARRAY) {
      rb_raise(rb_eArgError,
               "Expected array as initializer value for repeated field '%s'.", name);
    }
    ary = layout_get(self->descriptor->layout, Message_data(self), f);
    for (int i = 0; i < RARRAY_LEN(val); i++) {
      RepeatedField_push(ary, rb_ary_entry(val, i));
    }
  } else {
    layout_set(self->descriptor->layout, Message_data(self), f, val);
  }
  return 0;
}
예제 #9
0
VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
  upb_msg_field_iter it;
  for (upb_msg_field_begin(&it, layout->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);

    void* msg1_memory = slot_memory(layout, msg1, field);
    uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
    void* msg2_memory = slot_memory(layout, msg2, field);
    uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);

    if (upb_fielddef_containingoneof(field)) {
      if (*msg1_oneof_case != *msg2_oneof_case ||
          (*msg1_oneof_case == upb_fielddef_number(field) &&
           !native_slot_eq(upb_fielddef_type(field),
                           msg1_memory,
                           msg2_memory))) {
        return Qfalse;
      }
    } else if (is_map_field(field)) {
      if (!Map_eq(DEREF(msg1_memory, VALUE),
                  DEREF(msg2_memory, VALUE))) {
        return Qfalse;
      }
    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
      if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
                            DEREF(msg2_memory, VALUE))) {
        return Qfalse;
      }
    } else {
      if (slot_is_hasbit_set(layout, msg1, field) !=
	  slot_is_hasbit_set(layout, msg2, field) ||
          !native_slot_eq(upb_fielddef_type(field),
			  msg1_memory, msg2_memory)) {
        return Qfalse;
      }
    }
  }
  return Qtrue;
}
예제 #10
0
static void add_handlers_for_message(const void *closure, upb_handlers *h) {
    const upb_msgdef* msgdef = upb_handlers_msgdef(h);
    Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
    upb_msg_field_iter i;

    // If this is a mapentry message type, set up a special set of handlers and
    // bail out of the normal (user-defined) message type handling.
    if (upb_msgdef_mapentry(msgdef)) {
        add_handlers_for_mapentry(msgdef, h, desc);
        return;
    }

    // Ensure layout exists. We may be invoked to create handlers for a given
    // message if we are included as a submsg of another message type before our
    // class is actually built, so to work around this, we just create the layout
    // (and handlers, in the class-building function) on-demand.
    if (desc->layout == NULL) {
        desc->layout = create_layout(desc->msgdef);
    }

    for (upb_msg_field_begin(&i, desc->msgdef);
            !upb_msg_field_done(&i);
            upb_msg_field_next(&i)) {
        const upb_fielddef *f = upb_msg_iter_field(&i);
        size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
                        sizeof(MessageHeader);

        if (upb_fielddef_containingoneof(f)) {
            size_t oneof_case_offset =
                desc->layout->fields[upb_fielddef_index(f)].case_offset +
                sizeof(MessageHeader);
            add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
        } else if (is_map_field(f)) {
            add_handlers_for_mapfield(h, f, offset, desc);
        } else if (upb_fielddef_isseq(f)) {
            add_handlers_for_repeated_field(h, f, offset);
        } else {
            add_handlers_for_singular_field(h, f, offset);
        }
    }
}
예제 #11
0
static void putmsg(VALUE msg_rb, const Descriptor* desc,
                   upb_sink *sink, int depth) {
    MessageHeader* msg;
    upb_msg_field_iter i;
    upb_status status;

    upb_sink_startmsg(sink);

    // Protect against cycles (possible because users may freely reassign message
    // and repeated fields) by imposing a maximum recursion depth.
    if (depth > ENCODE_MAX_NESTING) {
        rb_raise(rb_eRuntimeError,
                 "Maximum recursion depth exceeded during encoding.");
    }

    TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);

    for (upb_msg_field_begin(&i, desc->msgdef);
            !upb_msg_field_done(&i);
            upb_msg_field_next(&i)) {
        upb_fielddef *f = upb_msg_iter_field(&i);
        uint32_t offset =
            desc->layout->fields[upb_fielddef_index(f)].offset +
            sizeof(MessageHeader);

        if (upb_fielddef_containingoneof(f)) {
            uint32_t oneof_case_offset =
                desc->layout->fields[upb_fielddef_index(f)].case_offset +
                sizeof(MessageHeader);
            // For a oneof, check that this field is actually present -- skip all the
            // below if not.
            if (DEREF(msg, oneof_case_offset, uint32_t) !=
                    upb_fielddef_number(f)) {
                continue;
            }
            // Otherwise, fall through to the appropriate singular-field handler
            // below.
        }

        if (is_map_field(f)) {
            VALUE map = DEREF(msg, offset, VALUE);
            if (map != Qnil) {
                putmap(map, f, sink, depth);
            }
        } else if (upb_fielddef_isseq(f)) {
            VALUE ary = DEREF(msg, offset, VALUE);
            if (ary != Qnil) {
                putary(ary, f, sink, depth);
            }
        } else if (upb_fielddef_isstring(f)) {
            VALUE str = DEREF(msg, offset, VALUE);
            if (RSTRING_LEN(str) > 0) {
                putstr(str, f, sink);
            }
        } else if (upb_fielddef_issubmsg(f)) {
            putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth);
        } else {
            upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));

#define T(upbtypeconst, upbtype, ctype, default_value)                \
  case upbtypeconst: {                                                \
      ctype value = DEREF(msg, offset, ctype);                        \
      if (value != default_value) {                                   \
        upb_sink_put##upbtype(sink, sel, value);                      \
      }                                                               \
    }                                                                 \
    break;

            switch (upb_fielddef_type(f)) {
                T(UPB_TYPE_FLOAT,  float,  float, 0.0)
                T(UPB_TYPE_DOUBLE, double, double, 0.0)
                T(UPB_TYPE_BOOL,   bool,   uint8_t, 0)
            case UPB_TYPE_ENUM:
                T(UPB_TYPE_INT32,  int32,  int32_t, 0)
                T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
                T(UPB_TYPE_INT64,  int64,  int64_t, 0)
                T(UPB_TYPE_UINT64, uint64, uint64_t, 0)

            case UPB_TYPE_STRING:
            case UPB_TYPE_BYTES:
            case UPB_TYPE_MESSAGE:
                rb_raise(rb_eRuntimeError, "Internal error.");
            }

#undef T

        }
    }

    upb_sink_endmsg(sink, &status);
}
예제 #12
0
const upb_fielddef* map_field_value(const upb_fielddef* field) {
    assert(is_map_field(field));
    const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
    return map_entry_value(subdef);
}