Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions ruby/ext/google/protobuf_c/defs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,17 @@ static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
field_proto,
FileBuilderContext_strdup(self->file_builder, default_value));
}

if (rb_funcall(options, rb_intern("key?"), 1,
ID2SYM(rb_intern("packed"))) == Qtrue) {
VALUE packed =
rb_hash_lookup(options, ID2SYM(rb_intern("packed")));
google_protobuf_FieldOptions *options =
google_protobuf_FieldDescriptorProto_mutable_options(
field_proto,
file_context->arena);
google_protobuf_FieldOptions_set_packed(options, RTEST(packed));
}
}

if (oneof_index >= 0) {
Expand Down Expand Up @@ -1614,26 +1625,29 @@ VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {

/*
* call-seq:
* MessageBuilderContext.repeated(name, type, number, type_class = nil)
* MessageBuilderContext.repeated(name, type, number, type_class = nil,
* options = nil)
*
* Defines a new repeated field on this message type with the given type, tag
* number, and type class (for message and enum fields). The type must be a Ruby
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
* string, if present (as accepted by FieldDescriptor#submsg_name=).
*/
VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
VALUE name, type, number, type_class;
VALUE name, type, number;
VALUE type_class = Qnil, options = Qnil;

rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);

if (argc < 3) {
rb_raise(rb_eArgError, "Expected at least 3 arguments.");
// Allow passing (name, type, number, options) or
// (name, type, number, type_class, options)
if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
options = type_class;
type_class = Qnil;
}
name = argv[0];
type = argv[1];
number = argv[2];
type_class = (argc > 3) ? argv[3] : Qnil;

msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
Qnil, -1);
options, -1);

return Qnil;
}
Expand Down
10 changes: 10 additions & 0 deletions ruby/tests/basic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -521,5 +521,15 @@ def test_map_freeze
assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
assert_raise(FrozenErrorType) { m.map_string_int32.clear }
end

def test_packed_unpacked
m = proto_module::PackedUnpackedMessage.new
m.packed_repeated_int32.replace([42, 84, 300])
assert_equal proto_module::PackedUnpackedMessage.encode(m), "\x0A\x04\x2A\x54\xAC\x02".b

m = proto_module::PackedUnpackedMessage.new
m.repeated_int32.replace([42, 84, 300])
assert_equal proto_module::PackedUnpackedMessage.encode(m), "\x58\x2A\x58\x54\x58\xAC\x02".b
end
end
end
10 changes: 10 additions & 0 deletions ruby/tests/basic_proto2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,15 @@ def test_file_descriptor
assert_equal "tests/basic_test_proto2.proto", file_descriptor.name
assert_equal :proto2, file_descriptor.syntax
end

def test_packed_unpacked
m = proto_module::PackedUnpackedMessage.new
m.packed_repeated_int32.replace([42, 84, 300])
assert_equal proto_module::PackedUnpackedMessage.encode(m), "\x0A\x04\x2A\x54\xAC\x02".b

m = proto_module::PackedUnpackedMessage.new
m.repeated_int32.replace([42, 84, 300])
assert_equal proto_module::PackedUnpackedMessage.encode(m), "\x58\x2A\x58\x54\x58\xAC\x02".b
end
end
end
20 changes: 20 additions & 0 deletions ruby/tests/basic_test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,23 @@ message MyStruct {
string string = 1;
google.protobuf.Struct struct = 2;
}

message PackedUnpackedMessage {
repeated int32 packed_repeated_int32 = 1;
repeated int64 packed_repeated_int64 = 2;
repeated uint32 packed_repeated_uint32 = 3;
repeated uint64 packed_repeated_uint64 = 4;
repeated bool packed_repeated_bool = 5;
repeated float packed_repeated_float = 6;
repeated double packed_repeated_double = 7;
repeated TestEnum packed_repeated_enum = 8;

repeated int32 repeated_int32 = 11 [packed=false];
repeated int64 repeated_int64 = 12 [packed=false];
repeated uint32 repeated_uint32 = 13 [packed=false];
repeated uint64 repeated_uint64 = 14 [packed=false];
repeated bool repeated_bool = 15 [packed=false];
repeated float repeated_float = 16 [packed=false];
repeated double repeated_double = 17 [packed=false];
repeated TestEnum repeated_enum = 18 [packed=false];
}
20 changes: 20 additions & 0 deletions ruby/tests/basic_test_proto2.proto
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,23 @@ message MyStruct {
optional string string = 1;
optional google.protobuf.Struct struct = 2;
}

message PackedUnpackedMessage {
repeated int32 packed_repeated_int32 = 1 [packed=true];
repeated int64 packed_repeated_int64 = 2 [packed=true];
repeated uint32 packed_repeated_uint32 = 3 [packed=true];
repeated uint64 packed_repeated_uint64 = 4 [packed=true];
repeated bool packed_repeated_bool = 5 [packed=true];
repeated float packed_repeated_float = 6 [packed=true];
repeated double packed_repeated_double = 7 [packed=true];
repeated TestEnum packed_repeated_enum = 8 [packed=true];

repeated int32 repeated_int32 = 11;
repeated int64 repeated_int64 = 12;
repeated uint32 repeated_uint32 = 13;
repeated uint64 repeated_uint64 = 14;
repeated bool repeated_bool = 15;
repeated float repeated_float = 16;
repeated double repeated_double = 17;
repeated TestEnum repeated_enum = 18;
}
5 changes: 5 additions & 0 deletions src/google/protobuf/compiler/ruby/ruby_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ void GenerateField(const FieldDescriptor* field, io::Printer* printer) {
DefaultValueForField(field));
}

if (field->is_packable()) {
printer->Print(", packed: $packed$", "packed",
field->is_packed() ? "true" : "false");
}

printer->Print("\n");
}
}
Expand Down