예제 #1
0
/*
 * call-seq:
 *     MessageClass.decode_json(data) => message
 *
 * Decodes the given data (as a string containing bytes in protocol buffers wire
 * format) under the interpretration given by this message class's definition
 * and returns a message object with the corresponding field values.
 */
VALUE Message_decode_json(VALUE klass, VALUE data) {
    VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
    Descriptor* desc = ruby_to_Descriptor(descriptor);
    VALUE msgklass = Descriptor_msgclass(descriptor);
    VALUE msg_rb;
    MessageHeader* msg;

    if (TYPE(data) != T_STRING) {
        rb_raise(rb_eArgError, "Expected string for JSON data.");
    }
    // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
    // convert, because string handlers pass data directly to message string
    // fields.

    msg_rb = rb_class_new_instance(0, NULL, msgklass);
    TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);

    {
        stackenv se;
        upb_sink sink;
        upb_json_parser* parser;
        stackenv_init(&se, "Error occurred during parsing: %s");

        upb_sink_reset(&sink, get_fill_handlers(desc), msg);
        parser = upb_json_parser_create(&se.env, &sink);
        upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
                          upb_json_parser_input(parser));

        stackenv_uninit(&se);
    }

    return msg_rb;
}
예제 #2
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");
    }
  }
}
예제 #3
0
/*
 * call-seq:
 *     MessageClass.decode(data) => message
 *
 * Decodes the given data (as a string containing bytes in protocol buffers wire
 * format) under the interpretration given by this message class's definition
 * and returns a message object with the corresponding field values.
 */
VALUE Message_decode(VALUE klass, VALUE data) {
    VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
    Descriptor* desc = ruby_to_Descriptor(descriptor);
    VALUE msgklass = Descriptor_msgclass(descriptor);
    VALUE msg_rb;
    MessageHeader* msg;

    if (TYPE(data) != T_STRING) {
        rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
    }

    msg_rb = rb_class_new_instance(0, NULL, msgklass);
    TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);

    {
        const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
        const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
        stackenv se;
        upb_sink sink;
        upb_pbdecoder* decoder;
        stackenv_init(&se, "Error occurred during parsing: %s");

        upb_sink_reset(&sink, h, msg);
        decoder = upb_pbdecoder_create(&se.env, method, &sink);
        upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
                          upb_pbdecoder_input(decoder));

        stackenv_uninit(&se);
    }

    return msg_rb;
}
예제 #4
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;
}
예제 #5
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;
}
예제 #6
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;
}
예제 #7
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;
}