WIP: first steps towards lazily creating wrappers.
This commit is contained in:
parent
9fdb2cf2bb
commit
969d245bd3
@ -298,6 +298,15 @@ static void *submsg_handler(void *closure, const void *hd) {
|
|||||||
return submsg;
|
return submsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* startwrapper(void* closure, const void* hd) {
|
||||||
|
char* msg = closure;
|
||||||
|
const submsg_handlerdata_t* submsgdata = hd;
|
||||||
|
|
||||||
|
set_hasbit(closure, submsgdata->hasbit);
|
||||||
|
|
||||||
|
return msg + submsgdata->ofs;
|
||||||
|
}
|
||||||
|
|
||||||
// Handler data for startmap/endmap handlers.
|
// Handler data for startmap/endmap handlers.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t ofs;
|
size_t ofs;
|
||||||
@ -541,6 +550,85 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool doublewrapper_handler(void* closure, const void* hd, double val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = DBL2NUM(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool floatwrapper_handler(void* closure, const void* hd, float val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = DBL2NUM(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool int64wrapper_handler(void* closure, const void* hd, int64_t val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = LL2NUM(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uint64wrapper_handler(void* closure, const void* hd, uint64_t val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = ULL2NUM(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool int32wrapper_handler(void* closure, const void* hd, int32_t val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = INT2NUM(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uint32wrapper_handler(void* closure, const void* hd, uint32_t val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = UINT2NUM(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t stringwrapper_handler(void* closure, const void* hd,
|
||||||
|
const char* ptr, size_t len,
|
||||||
|
const upb_bufhandle* handle) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = get_frozen_string(ptr, len, false);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t byteswrapper_handler(void* closure, const void* hd,
|
||||||
|
const char* ptr, size_t len,
|
||||||
|
const upb_bufhandle* handle) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
*rbval = get_frozen_string(ptr, len, true);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool boolwrapper_handler(void* closure, const void* hd, bool val) {
|
||||||
|
VALUE* rbval = closure;
|
||||||
|
if (val) {
|
||||||
|
*rbval = Qtrue;
|
||||||
|
} else {
|
||||||
|
*rbval = Qfalse;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_wrapper(const upb_msgdef* m) {
|
||||||
|
switch (upb_msgdef_wellknowntype(m)) {
|
||||||
|
case UPB_WELLKNOWN_DOUBLEVALUE:
|
||||||
|
case UPB_WELLKNOWN_FLOATVALUE:
|
||||||
|
case UPB_WELLKNOWN_INT64VALUE:
|
||||||
|
case UPB_WELLKNOWN_UINT64VALUE:
|
||||||
|
case UPB_WELLKNOWN_INT32VALUE:
|
||||||
|
case UPB_WELLKNOWN_UINT32VALUE:
|
||||||
|
case UPB_WELLKNOWN_STRINGVALUE:
|
||||||
|
case UPB_WELLKNOWN_BYTESVALUE:
|
||||||
|
case UPB_WELLKNOWN_BOOLVALUE:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set up handlers for a singular field.
|
// Set up handlers for a singular field.
|
||||||
static void add_handlers_for_singular_field(const Descriptor* desc,
|
static void add_handlers_for_singular_field(const Descriptor* desc,
|
||||||
upb_handlers* h,
|
upb_handlers* h,
|
||||||
@ -580,8 +668,11 @@ static void add_handlers_for_singular_field(const Descriptor* desc,
|
|||||||
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
|
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
|
||||||
attr.handler_data = newsubmsghandlerdata(
|
attr.handler_data = newsubmsghandlerdata(
|
||||||
h, offset, hasbit, field_type_class(desc->layout, f));
|
h, offset, hasbit, field_type_class(desc->layout, f));
|
||||||
upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
|
if (is_wrapper(upb_fielddef_msgsubdef(f))) {
|
||||||
break;
|
upb_handlers_setstartsubmsg(h, f, startwrapper, &attr);
|
||||||
|
} else {
|
||||||
|
upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,6 +714,43 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
|
|||||||
MESSAGE_FIELD_NO_HASBIT);
|
MESSAGE_FIELD_NO_HASBIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_handlers_for_wrapper(const upb_msgdef* msgdef,
|
||||||
|
upb_handlers* h) {
|
||||||
|
const upb_fielddef* f = upb_msgdef_itof(msgdef, 1);
|
||||||
|
switch (upb_msgdef_wellknowntype(msgdef)) {
|
||||||
|
case UPB_WELLKNOWN_DOUBLEVALUE:
|
||||||
|
upb_handlers_setdouble(h, f, doublewrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_FLOATVALUE:
|
||||||
|
upb_handlers_setfloat(h, f, floatwrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_INT64VALUE:
|
||||||
|
upb_handlers_setint64(h, f, int64wrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_UINT64VALUE:
|
||||||
|
upb_handlers_setuint64(h, f, uint64wrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_INT32VALUE:
|
||||||
|
upb_handlers_setint32(h, f, int32wrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_UINT32VALUE:
|
||||||
|
upb_handlers_setuint32(h, f, uint32wrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_STRINGVALUE:
|
||||||
|
upb_handlers_setstring(h, f, stringwrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_BYTESVALUE:
|
||||||
|
upb_handlers_setstring(h, f, byteswrapper_handler, NULL);
|
||||||
|
break;
|
||||||
|
case UPB_WELLKNOWN_BOOLVALUE:
|
||||||
|
upb_handlers_setbool(h, f, boolwrapper_handler, NULL);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
rb_raise(rb_eRuntimeError,
|
||||||
|
"Internal logic error with well-known types.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set up handlers for a oneof field.
|
// Set up handlers for a oneof field.
|
||||||
static void add_handlers_for_oneof_field(upb_handlers *h,
|
static void add_handlers_for_oneof_field(upb_handlers *h,
|
||||||
const upb_fielddef *f,
|
const upb_fielddef *f,
|
||||||
@ -706,6 +834,12 @@ void add_handlers_for_message(const void *closure, upb_handlers *h) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a wrapper type, use special handlers and bail.
|
||||||
|
if (is_wrapper(msgdef)) {
|
||||||
|
add_handlers_for_wrapper(msgdef, h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
upb_handlers_setunknown(h, unknown_field_handler, &attr);
|
upb_handlers_setunknown(h, unknown_field_handler, &attr);
|
||||||
|
|
||||||
for (upb_msg_field_begin(&i, desc->msgdef);
|
for (upb_msg_field_begin(&i, desc->msgdef);
|
||||||
|
@ -62,13 +62,12 @@ VALUE Message_alloc(VALUE klass) {
|
|||||||
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
Descriptor* desc = ruby_to_Descriptor(descriptor);
|
||||||
MessageHeader* msg;
|
MessageHeader* msg;
|
||||||
VALUE ret;
|
VALUE ret;
|
||||||
size_t size;
|
|
||||||
|
|
||||||
if (desc->layout == NULL) {
|
if (desc->layout == NULL) {
|
||||||
create_layout(desc);
|
create_layout(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
|
msg = (void*)ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
|
||||||
msg->descriptor = desc;
|
msg->descriptor = desc;
|
||||||
msg->unknown_fields = NULL;
|
msg->unknown_fields = NULL;
|
||||||
memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
|
memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
|
||||||
@ -109,25 +108,28 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if the field is a well known wrapper type
|
// Check if the field is a well known wrapper type
|
||||||
static bool is_wrapper_type_field(const MessageLayout* layout,
|
static bool is_wrapper_type_field(const upb_fielddef* field) {
|
||||||
const upb_fielddef* field) {
|
const upb_msgdef *m = upb_fielddef_msgsubdef(field);
|
||||||
const char* field_type_name = rb_class2name(field_type_class(layout, field));
|
switch (upb_msgdef_wellknowntype(m)) {
|
||||||
|
case UPB_WELLKNOWN_DOUBLEVALUE:
|
||||||
return strcmp(field_type_name, "Google::Protobuf::DoubleValue") == 0 ||
|
case UPB_WELLKNOWN_FLOATVALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::FloatValue") == 0 ||
|
case UPB_WELLKNOWN_INT64VALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::Int32Value") == 0 ||
|
case UPB_WELLKNOWN_UINT64VALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::Int64Value") == 0 ||
|
case UPB_WELLKNOWN_INT32VALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::UInt32Value") == 0 ||
|
case UPB_WELLKNOWN_UINT32VALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::UInt64Value") == 0 ||
|
case UPB_WELLKNOWN_STRINGVALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::BoolValue") == 0 ||
|
case UPB_WELLKNOWN_BYTESVALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::StringValue") == 0 ||
|
case UPB_WELLKNOWN_BOOLVALUE:
|
||||||
strcmp(field_type_name, "Google::Protobuf::BytesValue") == 0;
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a new Ruby wrapper type and set the initial value
|
// Get a new Ruby wrapper type and set the initial value
|
||||||
static VALUE ruby_wrapper_type(const MessageLayout* layout,
|
static VALUE ruby_wrapper_type(const MessageLayout* layout,
|
||||||
const upb_fielddef* field, const VALUE value) {
|
const upb_fielddef* field, const VALUE value) {
|
||||||
if (is_wrapper_type_field(layout, field) && value != Qnil) {
|
if (is_wrapper_type_field(field) && value != Qnil) {
|
||||||
VALUE hash = rb_hash_new();
|
VALUE hash = rb_hash_new();
|
||||||
rb_hash_aset(hash, rb_str_new2("value"), value);
|
rb_hash_aset(hash, rb_str_new2("value"), value);
|
||||||
{
|
{
|
||||||
@ -194,7 +196,7 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
|
|||||||
if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
|
if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
|
||||||
name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
|
name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
|
||||||
upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
|
upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
|
||||||
is_wrapper_type_field(self->descriptor->layout, test_f_wrapper)) {
|
is_wrapper_type_field(test_f_wrapper)) {
|
||||||
// It does exist!
|
// It does exist!
|
||||||
has_field = true;
|
has_field = true;
|
||||||
if (accessor_type == METHOD_SETTER) {
|
if (accessor_type == METHOD_SETTER) {
|
||||||
@ -329,10 +331,14 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|||||||
return layout_has(self->descriptor->layout, Message_data(self), f);
|
return layout_has(self->descriptor->layout, Message_data(self), f);
|
||||||
} else if (accessor_type == METHOD_WRAPPER_GETTER) {
|
} else if (accessor_type == METHOD_WRAPPER_GETTER) {
|
||||||
VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
|
VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
|
||||||
if (value != Qnil) {
|
switch (TYPE(value)) {
|
||||||
value = rb_funcall(value, rb_intern("value"), 0);
|
case T_DATA:
|
||||||
|
return rb_funcall(value, rb_intern("value"), 0);
|
||||||
|
case T_NIL:
|
||||||
|
return Qnil;
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
return value;
|
|
||||||
} else if (accessor_type == METHOD_WRAPPER_SETTER) {
|
} else if (accessor_type == METHOD_WRAPPER_SETTER) {
|
||||||
VALUE wrapper = ruby_wrapper_type(self->descriptor->layout, f, argv[1]);
|
VALUE wrapper = ruby_wrapper_type(self->descriptor->layout, f, argv[1]);
|
||||||
layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
|
layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
|
||||||
|
@ -1266,6 +1266,44 @@ module CommonTests
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_wrapper_getters
|
def test_wrapper_getters
|
||||||
|
run_asserts = ->(m) {
|
||||||
|
assert_equal 2.0, m.double_as_value
|
||||||
|
assert_equal 2.0, m.double.value
|
||||||
|
assert_equal 2.0, m.double_as_value
|
||||||
|
|
||||||
|
assert_equal 4.0, m.float_as_value
|
||||||
|
assert_equal 4.0, m.float.value
|
||||||
|
assert_equal 4.0, m.float_as_value
|
||||||
|
|
||||||
|
assert_equal 3, m.int32_as_value
|
||||||
|
assert_equal 3, m.int32.value
|
||||||
|
assert_equal 3, m.int32_as_value
|
||||||
|
|
||||||
|
assert_equal 4, m.int64_as_value
|
||||||
|
assert_equal 4, m.int64.value
|
||||||
|
assert_equal 4, m.int64_as_value
|
||||||
|
|
||||||
|
assert_equal 5, m.uint32_as_value
|
||||||
|
assert_equal 5, m.uint32.value
|
||||||
|
assert_equal 5, m.uint32_as_value
|
||||||
|
|
||||||
|
assert_equal 6, m.uint64_as_value
|
||||||
|
assert_equal 6, m.uint64.value
|
||||||
|
assert_equal 6, m.uint64_as_value
|
||||||
|
|
||||||
|
assert_equal true, m.bool_as_value
|
||||||
|
assert_equal true, m.bool.value
|
||||||
|
assert_equal true, m.bool_as_value
|
||||||
|
|
||||||
|
assert_equal 'str', m.string_as_value
|
||||||
|
assert_equal 'str', m.string.value
|
||||||
|
assert_equal 'str', m.string_as_value
|
||||||
|
|
||||||
|
assert_equal 'fun', m.bytes_as_value
|
||||||
|
assert_equal 'fun', m.bytes.value
|
||||||
|
assert_equal 'fun', m.bytes_as_value
|
||||||
|
}
|
||||||
|
|
||||||
m = proto_module::Wrapper.new(
|
m = proto_module::Wrapper.new(
|
||||||
double: Google::Protobuf::DoubleValue.new(value: 2.0),
|
double: Google::Protobuf::DoubleValue.new(value: 2.0),
|
||||||
float: Google::Protobuf::FloatValue.new(value: 4.0),
|
float: Google::Protobuf::FloatValue.new(value: 4.0),
|
||||||
@ -1279,24 +1317,10 @@ module CommonTests
|
|||||||
real_string: '100'
|
real_string: '100'
|
||||||
)
|
)
|
||||||
|
|
||||||
assert_equal 2.0, m.double_as_value
|
run_asserts.call(m)
|
||||||
assert_equal 2.0, m.double.value
|
serialized = proto_module::Wrapper::encode(m)
|
||||||
assert_equal 4.0, m.float_as_value
|
m2 = proto_module::Wrapper::decode(serialized)
|
||||||
assert_equal 4.0, m.float.value
|
run_asserts.call(m2)
|
||||||
assert_equal 3, m.int32_as_value
|
|
||||||
assert_equal 3, m.int32.value
|
|
||||||
assert_equal 4, m.int64_as_value
|
|
||||||
assert_equal 4, m.int64.value
|
|
||||||
assert_equal 5, m.uint32_as_value
|
|
||||||
assert_equal 5, m.uint32.value
|
|
||||||
assert_equal 6, m.uint64_as_value
|
|
||||||
assert_equal 6, m.uint64.value
|
|
||||||
assert_equal true, m.bool_as_value
|
|
||||||
assert_equal true, m.bool.value
|
|
||||||
assert_equal 'str', m.string_as_value
|
|
||||||
assert_equal 'str', m.string.value
|
|
||||||
assert_equal 'fun', m.bytes_as_value
|
|
||||||
assert_equal 'fun', m.bytes.value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_wrapper_setters_as_value
|
def test_wrapper_setters_as_value
|
||||||
@ -1443,7 +1467,7 @@ module CommonTests
|
|||||||
assert_raise(NoMethodError) { m.string_XXXXXXXXX }
|
assert_raise(NoMethodError) { m.string_XXXXXXXXX }
|
||||||
assert_raise(NoMethodError) { m.string_XXXXXXXXXX }
|
assert_raise(NoMethodError) { m.string_XXXXXXXXXX }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_converts_time
|
def test_converts_time
|
||||||
m = proto_module::TimeMessage.new
|
m = proto_module::TimeMessage.new
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user