Пример #1
0
static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
  RepeatedField* self;
  assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);

  if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
      RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
    rb_raise(cTypeError, "Expected repeated field array");
  }

  self = ruby_to_RepeatedField(val);
  if (self->field_type != upb_fielddef_type(field)) {
    rb_raise(cTypeError, "Repeated field array has wrong element type");
  }

  if (self->field_type == UPB_TYPE_MESSAGE) {
    if (self->field_type_class !=
        Descriptor_msgclass(get_def_obj(upb_fielddef_subdef(field)))) {
      rb_raise(cTypeError,
               "Repeated field array has wrong message class");
    }
  }


  if (self->field_type == UPB_TYPE_ENUM) {
    if (self->field_type_class !=
        EnumDescriptor_enummodule(get_def_obj(upb_fielddef_subdef(field)))) {
      rb_raise(cTypeError,
               "Repeated field array has wrong enum class");
    }
  }
}
Пример #2
0
VALUE field_type_class(const upb_fielddef* field) {
  VALUE type_class = Qnil;
  if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
    VALUE submsgdesc =
        get_def_obj(upb_fielddef_subdef(field));
    type_class = Descriptor_msgclass(submsgdesc);
  } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
    VALUE subenumdesc =
        get_def_obj(upb_fielddef_subdef(field));
    type_class = EnumDescriptor_enummodule(subenumdesc);
  }
  return type_class;
}
Пример #3
0
VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
  VALUE mod = rb_define_module_id(
      rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));

  upb_enum_iter it;
  for (upb_enum_begin(&it, enumdesc->enumdef);
       !upb_enum_done(&it);
       upb_enum_next(&it)) {
    const char* name = upb_enum_iter_name(&it);
    int32_t value = upb_enum_iter_number(&it);
    if (name[0] < 'A' || name[0] > 'Z') {
      rb_raise(rb_eTypeError,
               "Enum value '%s' does not start with an uppercase letter "
               "as is required for Ruby constants.",
               name);
    }
    rb_define_const(mod, name, INT2NUM(value));
  }

  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
  rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
  rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
  rb_iv_set(mod, kDescriptorInstanceVar, get_def_obj(enumdesc->enumdef));

  return mod;
}
Пример #4
0
static void check_map_field_type(VALUE val, const upb_fielddef* field) {
  const upb_fielddef* key_field = map_field_key(field);
  const upb_fielddef* value_field = map_field_value(field);
  Map* self;

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

  self = ruby_to_Map(val);
  if (self->key_type != upb_fielddef_type(key_field)) {
    rb_raise(cTypeError, "Map key type does not match field's key type");
  }
  if (self->value_type != upb_fielddef_type(value_field)) {
    rb_raise(cTypeError, "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(cTypeError,
               "Map value type has wrong message/enum class");
    }
  }
}
Пример #5
0
// Handler for a submessage field in a oneof.
static void *oneofsubmsg_handler(void *closure,
                                 const void *hd) {
    MessageHeader* msg = closure;
    const oneof_handlerdata_t *oneofdata = hd;
    uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);

    VALUE subdesc =
        get_def_obj((void*)oneofdata->md);
    VALUE subklass = Descriptor_msgclass(subdesc);
    VALUE submsg_rb;
    MessageHeader* submsg;

    if (oldcase != oneofdata->oneof_case_num ||
            DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
        DEREF(msg, oneofdata->ofs, VALUE) =
            rb_class_new_instance(0, NULL, subklass);
    }
    // Set the oneof case *after* allocating the new class instance -- otherwise,
    // if the Ruby GC is invoked as part of a call into the VM, it might invoke
    // our mark routines, and our mark routines might see the case value
    // indicating a VALUE is present and expect a valid VALUE. See comment in
    // layout_set() for more detail: basically, the change to the value and the
    // case must be atomic w.r.t. the Ruby VM.
    DEREF(msg, oneofdata->case_ofs, uint32_t) =
        oneofdata->oneof_case_num;

    submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
    TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
    return submsg;
}
Пример #6
0
// Handler to end a map entry: inserts the value defined during the message into
// the map. This is the 'endmsg' handler on the map entry msgdef.
static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
    map_parse_frame_t* frame = closure;
    const map_handlerdata_t* mapdata = hd;

    VALUE key = native_slot_get(
                    mapdata->key_field_type, Qnil,
                    &frame->key_storage);

    VALUE value_field_typeclass = Qnil;
    VALUE value;

    if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
            mapdata->value_field_type == UPB_TYPE_ENUM) {
        value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
    }

    value = native_slot_get(
                mapdata->value_field_type, value_field_typeclass,
                &frame->value_storage);

    Map_index_set(frame->map, key, value);
    free(frame);

    return true;
}
Пример #7
0
/*
 * call-seq:
 *     Descriptor.lookup(name) => FieldDescriptor
 *
 * Returns the field descriptor for the field with the given name, if present,
 * or nil if none.
 */
VALUE Descriptor_lookup(VALUE _self, VALUE name) {
  DEFINE_SELF(Descriptor, self, _self);
  const char* s = get_str(name);
  const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
  if (field == NULL) {
    return Qnil;
  }
  return get_def_obj(field);
}
Пример #8
0
/*
 * call-seq:
 *     DescriptorPool.lookup(name) => descriptor
 *
 * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
 * exists with the given name.
 */
VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
  DEFINE_SELF(DescriptorPool, self, _self);
  const char* name_str = get_str(name);
  const upb_def* def = upb_symtab_lookup(self->symtab, name_str);
  if (!def) {
    return Qnil;
  }
  return get_def_obj(def);
}
Пример #9
0
VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
  const upb_def *d = upb_fielddef_subdef(f);
  assert(d != NULL);

  VALUE descriptor = get_def_obj(d);
  VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);

  VALUE args[1] = { hash };
  return rb_class_new_instance(1, args, msgclass);
}
Пример #10
0
/*
 * call-seq:
 *     FieldDescriptor.subtype => message_or_enum_descriptor
 *
 * Returns the message or enum descriptor corresponding to this field's type if
 * it is a message or enum field, respectively, or nil otherwise. Cannot be
 * called *until* the containing message type is added to a pool (and thus
 * resolved).
 */
VALUE FieldDescriptor_subtype(VALUE _self) {
  DEFINE_SELF(FieldDescriptor, self, _self);
  if (!upb_fielddef_hassubdef(self->fielddef)) {
    return Qnil;
  }
  const upb_def* def = upb_fielddef_subdef(self->fielddef);
  if (def == NULL) {
    return Qnil;
  }
  return get_def_obj(def);
}
Пример #11
0
VALUE build_class_from_descriptor(Descriptor* desc) {
  const char *name;
  VALUE klass;

  if (desc->layout == NULL) {
    desc->layout = create_layout(desc->msgdef);
  }
  if (desc->fill_method == NULL) {
    desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
  }

  name = upb_msgdef_fullname(desc->msgdef);
  if (name == NULL) {
    rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
  }

  klass = rb_define_class_id(
      // Docs say this parameter is ignored. User will assign return value to
      // their own toplevel constant class name.
      rb_intern("Message"),
      rb_cObject);
  rb_ivar_set(klass, descriptor_instancevar_interned,
              get_def_obj(desc->msgdef));
  rb_define_alloc_func(klass, Message_alloc);
  rb_require("google/protobuf/message_exts");
  rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
  rb_extend_object(
      klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));

  rb_define_method(klass, "method_missing",
                   Message_method_missing, -1);
  rb_define_method(klass, "respond_to_missing?",
                   Message_respond_to_missing, -1);
  rb_define_method(klass, "initialize", Message_initialize, -1);
  rb_define_method(klass, "dup", Message_dup, 0);
  // Also define #clone so that we don't inherit Object#clone.
  rb_define_method(klass, "clone", Message_dup, 0);
  rb_define_method(klass, "==", Message_eq, 1);
  rb_define_method(klass, "hash", Message_hash, 0);
  rb_define_method(klass, "to_h", Message_to_h, 0);
  rb_define_method(klass, "to_hash", Message_to_h, 0);
  rb_define_method(klass, "inspect", Message_inspect, 0);
  rb_define_method(klass, "[]", Message_index, 1);
  rb_define_method(klass, "[]=", Message_index_set, 2);
  rb_define_singleton_method(klass, "decode", Message_decode, 1);
  rb_define_singleton_method(klass, "encode", Message_encode, 1);
  rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
  rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
  rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);

  return klass;
}
Пример #12
0
/*
 * call-seq:
 *     Descriptor.each(&block)
 *
 * Iterates over fields in this message type, yielding to the block on each one.
 */
VALUE Descriptor_each(VALUE _self) {
  DEFINE_SELF(Descriptor, self, _self);

  upb_msg_iter it;
  for (upb_msg_begin(&it, self->msgdef);
       !upb_msg_done(&it);
       upb_msg_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);
    VALUE obj = get_def_obj(field);
    rb_yield(obj);
  }
  return Qnil;
}
Пример #13
0
// Appends a submessage to a repeated field (a regular Ruby array for now).
static void *appendsubmsg_handler(void *closure, const void *hd) {
    VALUE ary = (VALUE)closure;
    const submsg_handlerdata_t *submsgdata = hd;
    VALUE subdesc =
        get_def_obj((void*)submsgdata->md);
    VALUE subklass = Descriptor_msgclass(subdesc);
    MessageHeader* submsg;

    VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass);
    RepeatedField_push(ary, submsg_rb);

    TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
    return submsg;
}
Пример #14
0
// Sets a non-repeated submessage field in a message.
static void *submsg_handler(void *closure, const void *hd) {
  MessageHeader* msg = closure;
  const submsg_handlerdata_t* submsgdata = hd;
  VALUE subdesc =
      get_def_obj((void*)submsgdata->md);
  VALUE subklass = Descriptor_msgclass(subdesc);

  if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
    DEREF(msg, submsgdata->ofs, VALUE) =
        rb_class_new_instance(0, NULL, subklass);
  }

  VALUE submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
  MessageHeader* submsg;
  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
  return submsg;
}
Пример #15
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);
        }
    }
}