proto3: make strings default to "" instead of NULL

The spec talks about "empty string" and other languages like C#
return a zero length string and not null.
This is useful because when moving from proto2's "required string"
to a proto3's plain string we will be guaranteed that we
never get a null pointer.
The tradeoff is adding a special case to the library but avoiding
a lot of null checks in the calling code.
The current code is already special casing "" in pack_string.
This commit is contained in:
Paolo Borelli 2017-05-26 18:24:32 +02:00
parent a8921fe7dc
commit 2a46af4278
6 changed files with 24 additions and 1 deletions

View File

@ -21,3 +21,8 @@ global:
local:
*;
};
LIBPROTOBUF_C_1.3.0 {
global:
protobuf_c_empty_string;
} LIBPROTOBUF_C_1.0.0;

View File

@ -84,6 +84,8 @@
# define PROTOBUF_C_UNPACK_ERROR(...)
#endif
const char protobuf_c_empty_string[] = "";
/**
* Internal `ProtobufCMessage` manipulation macro.
*
@ -554,6 +556,9 @@ field_is_zeroish(const ProtobufCFieldDescriptor *field,
ret = (0 == *(const double *) member);
break;
case PROTOBUF_C_TYPE_STRING:
ret = (NULL == *(const char * const *) member) ||
('\0' == **(const char * const *) member);
break;
case PROTOBUF_C_TYPE_BYTES:
case PROTOBUF_C_TYPE_MESSAGE:
ret = (NULL == *(const void * const *) member);

View File

@ -237,6 +237,9 @@ PROTOBUF_C__BEGIN_DECLS
#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9
#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af
/* Empty string used for initializers */
extern const char protobuf_c_empty_string[];
/**
* \defgroup api Public API
*

View File

@ -129,6 +129,9 @@ void FieldGenerator::GenerateDescriptorInitializerGeneric(io::Printer* printer,
variables["default_value"] = string("&")
+ FullNameToLower(descriptor_->full_name())
+ "__default_value";
} else if (FieldSyntax(descriptor_) == 3 &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
variables["default_value"] = "&protobuf_c_empty_string";
} else {
variables["default_value"] = "NULL";
}

View File

@ -125,8 +125,10 @@ void StringFieldGenerator::GenerateStaticInit(io::Printer* printer) const
std::map<string, string> vars;
if (descriptor_->has_default_value()) {
vars["default"] = GetDefaultValue();
} else {
} else if (FieldSyntax(descriptor_) == 2) {
vars["default"] = "NULL";
} else {
vars["default"] = "(char *)protobuf_c_empty_string";
}
switch (descriptor_->label()) {
case FieldDescriptor::LABEL_REQUIRED:

View File

@ -51,6 +51,11 @@ int main(void)
person2 = foo__person__unpack (NULL, size, packed);
assert (person2 != NULL);
assert (person2->id == 42);
#ifndef PROTO3
assert (person2->email == NULL);
#else
assert (strcmp (person2->email, "") == 0);
#endif
assert (strcmp (person2->name, "dave b") == 0);
assert (person2->n_phone == 1);
assert (strcmp (person2->phone[0]->number, "1234") == 0);