diff options
-rw-r--r-- | docs/migration.rst | 19 | ||||
-rwxr-xr-x | generator/nanopb_generator.py | 30 | ||||
-rw-r--r-- | generator/proto/nanopb.proto | 3 |
3 files changed, 42 insertions, 10 deletions
diff --git a/docs/migration.rst b/docs/migration.rst index 5f7246f5..d5ded643 100644 --- a/docs/migration.rst +++ b/docs/migration.rst @@ -11,6 +11,25 @@ are included, in order to make it easier to find this document. .. contents :: +Nanopb-0.3.2 (2015-01-xx) +========================= + +Add support for OneOfs +---------------------- +**Rationale:** Previously nanopb did not support the *oneof* construct in +*.proto* files. Those fields were generated as regular *optional* fields. + +**Changes:** OneOfs are now generated as C unions. Callback fields are not +supported inside oneof and generator gives an error. + +**Required actions:** The generator option *no_unions* can be used to restore old +behaviour and to allow callbacks to be used. To use unions, one change is +needed: use *which_xxxx* field to detect which field is present, instead +of *has_xxxx*. Compare the value against *MyStruct_myfield_tag*. + +**Error indications:** Generator error: "Callback fields inside of oneof are +not supported". Compiler error: "Message" has no member named "has_xxxx". + Nanopb-0.3.0 (2014-08-26) ========================= diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py index 3f309a4d..0d7be492 100755 --- a/generator/nanopb_generator.py +++ b/generator/nanopb_generator.py @@ -591,7 +591,7 @@ class OneOf(Field): def add_field(self, field): if field.allocation == 'CALLBACK': raise Exception("Callback fields inside of oneof are not supported" - + " (field %s)" % field.fullname) + + " (field %s)" % field.name) field.union_name = self.name field.rules = 'ONEOF' @@ -652,13 +652,20 @@ class Message: def __init__(self, names, desc, message_options): self.name = names self.fields = [] - self.oneofs = [] + self.oneofs = {} + no_unions = [] if hasattr(desc, 'oneof_decl'): - for f in desc.oneof_decl: - oneof = OneOf(self.name, f) - self.oneofs.append(oneof) - self.fields.append(oneof) + for i, f in enumerate(desc.oneof_decl): + oneof_options = get_nanopb_suboptions(desc, message_options, self.name + f.name) + if oneof_options.no_unions: + no_unions.append(i) # No union, but add fields normally + elif oneof_options.type == nanopb_pb2.FT_IGNORE: + pass # No union and skip fields also + else: + oneof = OneOf(self.name, f) + self.oneofs[i] = oneof + self.fields.append(oneof) for f in desc.field: field_options = get_nanopb_suboptions(f, message_options, self.name + f.name) @@ -666,8 +673,11 @@ class Message: continue field = Field(self.name, f, field_options) - if hasattr(f, 'oneof_index') and f.HasField('oneof_index'): - self.oneofs[f.oneof_index].add_field(field) + if (hasattr(f, 'oneof_index') and + f.HasField('oneof_index') and + f.oneof_index not in no_unions): + if f.oneof_index in self.oneofs: + self.oneofs[f.oneof_index].add_field(field) else: self.fields.append(field) @@ -734,7 +744,7 @@ class Message: '''Returns number of required fields inside this message''' count = 0 for f in self.fields: - if f not in self.oneofs: + if not isinstance(f, OneOf): if f.rules == 'REQUIRED': count += 1 return count @@ -742,7 +752,7 @@ class Message: def count_all_fields(self): count = 0 for f in self.fields: - if f in self.oneofs: + if isinstance(f, OneOf): count += len(f.fields) else: count += 1 diff --git a/generator/proto/nanopb.proto b/generator/proto/nanopb.proto index e830ec2c..a1b24936 100644 --- a/generator/proto/nanopb.proto +++ b/generator/proto/nanopb.proto @@ -53,6 +53,9 @@ message NanoPBOptions { // Skip this message optional bool skip_message = 6 [default = false]; + + // Generate oneof fields as normal optional fields instead of union. + optional bool no_unions = 8 [default = false]; } // Extensions to protoc 'Descriptor' type in order to define options |