summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xgenerator/nanopb_generator.py12
-rw-r--r--generator/proto/nanopb.proto3
-rw-r--r--pb.h13
-rw-r--r--pb_decode.c3
-rw-r--r--pb_encode.c17
5 files changed, 42 insertions, 6 deletions
diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py
index 973c7610..185a97bb 100755
--- a/generator/nanopb_generator.py
+++ b/generator/nanopb_generator.py
@@ -258,16 +258,18 @@ class Field:
# Check field rules, i.e. required/optional/repeated.
can_be_static = True
- if desc.label == FieldD.LABEL_REQUIRED:
- self.rules = 'REQUIRED'
- elif desc.label == FieldD.LABEL_OPTIONAL:
- self.rules = 'OPTIONAL'
- elif desc.label == FieldD.LABEL_REPEATED:
+ if desc.label == FieldD.LABEL_REPEATED:
self.rules = 'REPEATED'
if self.max_count is None:
can_be_static = False
else:
self.array_decl = '[%d]' % self.max_count
+ elif field_options.HasField("proto3"):
+ self.rules = 'SINGULAR'
+ elif desc.label == FieldD.LABEL_REQUIRED:
+ self.rules = 'REQUIRED'
+ elif desc.label == FieldD.LABEL_OPTIONAL:
+ self.rules = 'OPTIONAL'
else:
raise NotImplementedError(desc.label)
diff --git a/generator/proto/nanopb.proto b/generator/proto/nanopb.proto
index 8aab19a1..b9961c88 100644
--- a/generator/proto/nanopb.proto
+++ b/generator/proto/nanopb.proto
@@ -66,6 +66,9 @@ message NanoPBOptions {
// decode oneof as anonymous union
optional bool anonymous_oneof = 11 [default = false];
+
+ // Proto3 singular field does not generate a "has_" flag
+ optional bool proto3 = 12 [default = false];
}
// Extensions to protoc 'Descriptor' type in order to define options
diff --git a/pb.h b/pb.h
index 4576f79a..0e1e92d5 100644
--- a/pb.h
+++ b/pb.h
@@ -413,6 +413,10 @@ struct pb_extension_s {
pb_delta(st, has_ ## m, m), \
pb_membersize(st, m), 0, ptr}
+#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
+ fd, 0, pb_membersize(st, m), 0, ptr}
+
/* Repeated fields have a _count field and also the maximum number of entries. */
#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \
@@ -444,6 +448,11 @@ struct pb_extension_s {
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
+/* Same as optional fields*/
+#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
+ fd, 0, pb_membersize(st, m[0]), 0, ptr}
+
/* Repeated fields have a _count field and a pointer to array of pointers */
#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
@@ -458,6 +467,10 @@ struct pb_extension_s {
#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
+
+#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \
+ {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
+ fd, 0, pb_membersize(st, m), 0, ptr}
#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
diff --git a/pb_decode.c b/pb_decode.c
index 7a4e29a8..1f6aeae0 100644
--- a/pb_decode.c
+++ b/pb_decode.c
@@ -360,7 +360,8 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
return func(stream, iter->pos, iter->pData);
case PB_HTYPE_OPTIONAL:
- *(bool*)iter->pSize = true;
+ if (iter->pSize != iter->pData)
+ *(bool*)iter->pSize = true;
return func(stream, iter->pos, iter->pData);
case PB_HTYPE_REPEATED:
diff --git a/pb_encode.c b/pb_encode.c
index 4685614c..4f57fa5f 100644
--- a/pb_encode.c
+++ b/pb_encode.c
@@ -210,6 +210,23 @@ static bool checkreturn encode_basic_field(pb_ostream_t *stream,
if (field->size_offset)
pSize = (const char*)pData + field->size_offset;
+ else if (!field->size_offset && PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
+ {
+ /* In proto3 there are optional fields but no has_ flag, do not encode this fields
+ * when value is default or empty. */
+ if(PB_LTYPE(field->type) == PB_LTYPE_BYTES){
+ const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData;
+ if(bytes->size == 0)
+ implicit_has = false;
+ else if ((PB_LTYPE(field->type) == PB_LTYPE_STRING && *(const char*)pData == '\0') ||
+ (field->data_size == sizeof(uint_least8_t) && *(const uint_least8_t*)pData == 0) ||
+ (field->data_size == sizeof(uint_least16_t) && *(const uint_least16_t*)pData == 0) ||
+ (field->data_size == sizeof(uint32_t) && *(const uint_least32_t*)pData == 0) ||
+ (field->data_size == sizeof(uint64_t) && *(const uint_least64_t*)pData == 0))
+ implicit_has = false;
+ }
+ pSize = &implicit_has;
+ }
else
pSize = &implicit_has;