+class ExtensionRange(Field):
+ def __init__(self, struct_name, range_start, field_options):
+ '''Implements a special pb_extension_t* field in an extensible message
+ structure. The range_start signifies the index at which the extensions
+ start. Not necessarily all tags above this are extensions, it is merely
+ a speed optimization.
+ '''
+ self.tag = range_start
+ self.struct_name = struct_name
+ self.name = 'extensions'
+ self.pbtype = 'EXTENSION'
+ self.rules = 'OPTIONAL'
+ self.allocation = 'CALLBACK'
+ self.ctype = 'pb_extension_t'
+ self.array_decl = ''
+ self.default = None
+ self.max_size = 0
+ self.max_count = 0
+
+ def __str__(self):
+ return ' pb_extension_t *extensions;'
+
+ def types(self):
+ return ''
+
+ def tags(self):
+ return ''
+
+ def encoded_size(self, allmsgs):
+ # We exclude extensions from the count, because they cannot be known
+ # until runtime. Other option would be to return None here, but this
+ # way the value remains useful if extensions are not used.
+ return EncodedSize(0)
+
+class ExtensionField(Field):
+ def __init__(self, struct_name, desc, field_options):
+ self.fullname = struct_name + desc.name
+ self.extendee_name = names_from_type_name(desc.extendee)
+ Field.__init__(self, self.fullname + 'struct', desc, field_options)
+
+ if self.rules != 'OPTIONAL':
+ self.skip = True
+ else:
+ self.skip = False
+ self.rules = 'OPTEXT'
+
+ def tags(self):
+ '''Return the #define for the tag number of this field.'''
+ identifier = '%s_tag' % self.fullname
+ return '#define %-40s %d\n' % (identifier, self.tag)
+
+ def extension_decl(self):
+ '''Declaration of the extension type in the .pb.h file'''
+ if self.skip:
+ msg = '/* Extension field %s was skipped because only "optional"\n' % self.fullname
+ msg +=' type of extension fields is currently supported. */\n'
+ return msg
+
+ return ('extern const pb_extension_type_t %s; /* field type: %s */\n' %
+ (self.fullname, str(self).strip()))
+
+ def extension_def(self):
+ '''Definition of the extension type in the .pb.c file'''
+
+ if self.skip:
+ return ''
+
+ result = 'typedef struct {\n'
+ result += str(self)
+ result += '\n} %s;\n\n' % self.struct_name
+ result += ('static const pb_field_t %s_field = \n %s;\n\n' %
+ (self.fullname, self.pb_field_t(None)))
+ result += 'const pb_extension_type_t %s = {\n' % self.fullname
+ result += ' NULL,\n'
+ result += ' NULL,\n'
+ result += ' &%s_field\n' % self.fullname
+ result += '};\n'
+ return result
+
+
+# ---------------------------------------------------------------------------
+# Generation of oneofs (unions)
+# ---------------------------------------------------------------------------
+
+class OneOf(Field):
+ def __init__(self, struct_name, oneof_desc):
+ self.struct_name = struct_name
+ self.name = oneof_desc.name
+ self.ctype = 'union'
+ self.fields = []
+ self.allocation = 'ONEOF'
+ self.default = None
+ self.rules = 'ONEOF'
+
+ def add_field(self, field):
+ if field.allocation == 'CALLBACK':
+ raise Exception("Callback fields inside of oneof are not supported"
+ + " (field %s)" % field.name)
+
+ field.union_name = self.name
+ field.rules = 'ONEOF'
+ self.fields.append(field)
+ self.fields.sort(key = lambda f: f.tag)
+
+ # Sort by the lowest tag number inside union
+ self.tag = min([f.tag for f in self.fields])
+
+ def __cmp__(self, other):
+ return cmp(self.tag, other.tag)
+
+ def __str__(self):
+ result = ''
+ if self.fields:
+ result += ' pb_size_t which_' + self.name + ";\n"
+ result += ' union {\n'
+ for f in self.fields:
+ result += ' ' + str(f).replace('\n', '\n ') + '\n'
+ result += ' } ' + self.name + ';'
+ return result
+
+ def types(self):
+ return ''.join([f.types() for f in self.fields])
+
+ def get_dependencies(self):
+ deps = []
+ for f in self.fields:
+ deps += f.get_dependencies()
+ return deps
+
+ def get_initializer(self, null_init):
+ return '0, {' + self.fields[0].get_initializer(null_init) + '}'
+
+ def default_decl(self, declaration_only = False):
+ return None
+
+ def tags(self):
+ return '\n'.join([f.tags() for f in self.fields])
+
+ def pb_field_t(self, prev_field_name):
+ result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields])
+ return result
+
+ def largest_field_value(self):
+ return max([f.largest_field_value() for f in self.fields])
+
+ def encoded_size(self, allmsgs):
+ largest = EncodedSize(0)
+ for f in self.fields:
+ size = f.encoded_size(allmsgs)
+ if size is None:
+ return None
+ elif size.symbols:
+ return None # Cannot resolve maximum of symbols
+ elif size.value > largest.value:
+ largest = size
+
+ return largest
+