Ejemplo n.º 1
0
  def _GenerateEnumToString(self, cpp_namespace, type_):
    """Generates ToString() which gets the string representation of an enum.
    """
    c = Code()
    classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))

    if cpp_namespace is not None:
      c.Append('// static')
    maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace

    c.Sblock('std::string %sToString(%s enum_param) {' %
                 (maybe_namespace, classname))
    c.Sblock('switch (enum_param) {')
    for enum_value in self._type_helper.FollowRef(type_).enum_values:
      name = enum_value.name
      if 'camel_case_enum_to_string' in self._namespace.compiler_options:
        name = enum_value.CamelName()
      (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value))
        .Append('  return "%s";' % name))
    (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_))
      .Append('  return "";')
      .Eblock('}')
      .Append('NOTREACHED();')
      .Append('return "";')
      .Eblock('}')
    )
    return c
Ejemplo n.º 2
0
  def _GenerateEnumFromString(self, cpp_namespace, type_):
    """Generates FromClassNameString() which gets an enum from its string
    representation.
    """
    c = Code()
    classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))

    if cpp_namespace is not None:
      c.Append('// static')
    maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace

    c.Sblock('%s%s %sParse%s(const std::string& enum_string) {' %
                 (maybe_namespace, classname, maybe_namespace, classname))
    for _, enum_value in enumerate(
          self._type_helper.FollowRef(type_).enum_values):
      # This is broken up into all ifs with no else ifs because we get
      # "fatal error C1061: compiler limit : blocks nested too deeply"
      # on Windows.
      (c.Append('if (enum_string == "%s")' % enum_value.name)
        .Append('  return %s;' %
            self._type_helper.GetEnumValue(type_, enum_value)))
    (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_))
      .Eblock('}')
    )
    return c
Ejemplo n.º 3
0
 def _FindType(self, full_name):
     """Finds the model.Type with name |qualified_name|. If it's not from
 |self._default_namespace| then it needs to be qualified.
 """
     namespace = self._schema_loader.ResolveType(full_name,
                                                 self._default_namespace)
     if namespace is None:
         raise KeyError('Cannot resolve type %s. Maybe it needs a prefix '
                        'if it comes from another namespace?' % full_name)
     return namespace.types[schema_util.StripNamespace(full_name)]
Ejemplo n.º 4
0
    def _GenerateType(self, cpp_namespace, type_):
        """Generates the function definitions for a type.
    """
        classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
        c = Code()

        if type_.functions:
            # Wrap functions within types in the type's namespace.
            (c.Append('namespace %s {' % classname).Append())
            for function in type_.functions.values():
                c.Cblock(self._GenerateFunction(function))
            c.Append('}  // namespace %s' % classname)
        elif type_.property_type == PropertyType.ARRAY:
            c.Cblock(self._GenerateType(cpp_namespace, type_.item_type))
        elif type_.property_type in (PropertyType.CHOICES,
                                     PropertyType.OBJECT):
            if cpp_namespace is None:
                classname_in_namespace = classname
            else:
                classname_in_namespace = '%s::%s' % (cpp_namespace, classname)

            if type_.property_type == PropertyType.OBJECT:
                c.Cblock(
                    self._GeneratePropertyFunctions(classname_in_namespace,
                                                    type_.properties.values()))
            else:
                c.Cblock(
                    self._GenerateTypes(classname_in_namespace, type_.choices))

            (c.Append('%s::%s()' % (classname_in_namespace, classname)).Cblock(
                self._GenerateInitializersAndBody(type_)).Append(
                    '%s::~%s() {}' % (classname_in_namespace, classname)))
            # Note: we use 'rhs' because some API objects have a member 'other'.
            (c.Append('%s::%s(%s&& rhs)' %
                      (classname_in_namespace, classname, classname)).Cblock(
                          self._GenerateMoveCtor(type_)).Append(
                              '%s& %s::operator=(%s&& rhs)' %
                              (classname_in_namespace, classname_in_namespace,
                               classname)).Cblock(
                                   self._GenerateMoveAssignOperator(type_)))
            if type_.origin.from_json:
                c.Cblock(
                    self._GenerateTypePopulate(classname_in_namespace, type_))
                if cpp_namespace is None:  # only generate for top-level types
                    c.Cblock(
                        self._GenerateTypeFromValue(classname_in_namespace,
                                                    type_))
            if type_.origin.from_client:
                c.Cblock(
                    self._GenerateTypeToValue(classname_in_namespace, type_))
        elif type_.property_type == PropertyType.ENUM:
            (c.Cblock(self._GenerateEnumToString(cpp_namespace, type_)).Cblock(
                self._GenerateEnumFromString(cpp_namespace, type_)))

        return c
Ejemplo n.º 5
0
 def _GenerateTypeFromValue(self, cpp_namespace, type_):
     classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
     c = Code()
     (c.Append('// static').Append(
         'scoped_ptr<%s> %s::FromValue(const base::Value& value) {' %
         (classname, cpp_namespace)).Append(
             '  scoped_ptr<%s> out(new %s());' %
             (classname, classname)).Append(
                 '  if (!Populate(value, out.get()))').Append(
                     '    return scoped_ptr<%s>();' %
                     classname).Append('  return out.Pass();').Append('}'))
     return c
Ejemplo n.º 6
0
    def _GenerateTypePopulate(self, cpp_namespace, type_):
        """Generates the function for populating a type given a pointer to it.

    E.g for type "Foo", generates Foo::Populate()
    """
        classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
        c = Code()
        (c.Append('// static').Append('bool %(namespace)s::Populate(').Sblock(
            '    const base::Value& value, %(name)s* out) {'))
        if type_.property_type == PropertyType.CHOICES:
            for choice in type_.choices:
                value_type = cpp_util.GetValueType(
                    self._type_helper.FollowRef(choice))
                (c.Sblock('if (value.IsType(%s)) {' % value_type).Concat(
                    self._GeneratePopulateVariableFromValue(
                        choice,
                        '(&value)',
                        'out->as_%s' % choice.unix_name,
                        'false',
                        is_ptr=True)).Append('return true;').Eblock('}'))
            c.Append('return false;')
        elif type_.property_type == PropertyType.OBJECT:
            (c.Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))').
             Append('  return false;'))
            if type_.properties or type_.additional_properties is not None:
                c.Append('const base::DictionaryValue* dict = '
                         'static_cast<const base::DictionaryValue*>(&value);')
            for prop in type_.properties.values():
                c.Concat(self._InitializePropertyToDefault(prop, 'out'))
            for prop in type_.properties.values():
                c.Concat(
                    self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
            if type_.additional_properties is not None:
                if type_.additional_properties.property_type == PropertyType.ANY:
                    c.Append(
                        'out->additional_properties.MergeDictionary(dict);')
                else:
                    cpp_type = self._type_helper.GetCppType(
                        type_.additional_properties, is_in_container=True)
                    (c.Append('for (base::DictionaryValue::Iterator it(*dict);'
                              ).Sblock('     !it.IsAtEnd(); it.Advance()) {').
                     Append('%s tmp;' % cpp_type).Concat(
                         self._GeneratePopulateVariableFromValue(
                             type_.additional_properties, '(&it.value())',
                             'tmp', 'false')).Append(
                                 'out->additional_properties[it.key()] = tmp;'
                             ).Eblock('}'))
            c.Append('return true;')
        (c.Eblock('}').Substitute({
            'namespace': cpp_namespace,
            'name': classname
        }))
        return c
Ejemplo n.º 7
0
 def _GenerateTypeFromValue(self, cpp_namespace, type_):
     classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
     c = Code()
     (c.Append('// static').Append(
         'std::unique_ptr<%s> %s::FromValue(%s) {' %
         (classname, cpp_namespace,
          self._GenerateParams(('const base::Value& value', )))))
     if self._generate_error_messages:
         c.Append('DCHECK(error);')
     (c.Append('  std::unique_ptr<%s> out(new %s());' %
               (classname, classname)).Append('  if (!Populate(%s))' %
                                              self._GenerateArgs(
                                                  ('value', 'out.get()'))).
      Append('    return nullptr;').Append('  return out;').Append('}'))
     return c
Ejemplo n.º 8
0
    def _CreateValueFromType(self, cpp_namespace, type_, var, is_ptr=False):
        """Creates a base::Value given a type. Generated code passes ownership
    to caller.

    var: variable or variable*

    E.g for std::string, generate new base::StringValue(var)
    """
        underlying_type = self._type_helper.FollowRef(type_)
        if (underlying_type.property_type == PropertyType.CHOICES
                or underlying_type.property_type == PropertyType.OBJECT):
            if is_ptr:
                return '(%s)->ToValue().release()' % var
            else:
                return '(%s).ToValue().release()' % var
        elif (underlying_type.property_type == PropertyType.ANY
              or underlying_type.property_type == PropertyType.FUNCTION):
            if is_ptr:
                vardot = '(%s)->' % var
            else:
                vardot = '(%s).' % var
            return '%sDeepCopy()' % vardot
        elif underlying_type.property_type == PropertyType.ENUM:
            classname = cpp_util.Classname(
                schema_util.StripNamespace(underlying_type.name))
            return 'new base::StringValue(%sToString(%s))' % (classname, var)
        elif underlying_type.property_type == PropertyType.BINARY:
            if is_ptr:
                vardot = var + '->'
            else:
                vardot = var + '.'
            return (
                'base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())'
                % (vardot, vardot))
        elif underlying_type.property_type == PropertyType.ARRAY:
            return '%s.release()' % self._util_cc_helper.CreateValueFromArray(
                cpp_namespace, underlying_type, var, is_ptr)
        elif underlying_type.property_type.is_fundamental:
            if is_ptr:
                var = '*%s' % var
            if underlying_type.property_type == PropertyType.STRING:
                return 'new base::StringValue(%s)' % var
            else:
                return 'new base::FundamentalValue(%s)' % var
        else:
            raise NotImplementedError('Conversion of %s to base::Value not '
                                      'implemented' % repr(type_.type_))
Ejemplo n.º 9
0
    def _GenerateType(self, cpp_namespace, type_):
        """Generates the function definitions for a type.
    """
        classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
        c = Code()

        if type_.functions:
            # Wrap functions within types in the type's namespace.
            (c.Append('namespace %s {' % classname).Append())
            for function in type_.functions.values():
                c.Cblock(self._GenerateFunction(function))
            c.Append('}  // namespace %s' % classname)
        elif type_.property_type == PropertyType.ARRAY:
            c.Cblock(self._GenerateType(cpp_namespace, type_.item_type))
        elif (type_.property_type == PropertyType.OBJECT
              or type_.property_type == PropertyType.CHOICES):
            if cpp_namespace is None:
                classname_in_namespace = classname
            else:
                classname_in_namespace = '%s::%s' % (cpp_namespace, classname)

            if type_.property_type == PropertyType.OBJECT:
                c.Cblock(
                    self._GeneratePropertyFunctions(classname_in_namespace,
                                                    type_.properties.values()))
            else:
                c.Cblock(
                    self._GenerateTypes(classname_in_namespace, type_.choices))

            (c.Append('%s::%s()' % (classname_in_namespace, classname)).Cblock(
                self._GenerateInitializersAndBody(type_)).Append(
                    '%s::~%s() {}' %
                    (classname_in_namespace, classname)).Append())
            if type_.origin.from_json:
                c.Cblock(
                    self._GenerateTypePopulate(classname_in_namespace, type_))
            if type_.origin.from_client:
                c.Cblock(
                    self._GenerateTypeToValue(classname_in_namespace, type_))
        elif type_.property_type == PropertyType.ENUM:
            (c.Cblock(self._GenerateEnumToString(cpp_namespace, type_)).Cblock(
                self._GenerateEnumFromString(cpp_namespace, type_)))

        return c
Ejemplo n.º 10
0
  def _GenerateTypePopulate(self, cpp_namespace, type_):
    """Generates the function for populating a type given a pointer to it.

    E.g for type "Foo", generates Foo::Populate()
    """
    classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
    c = Code()
    (c.Append('// static')
      .Append('bool %(namespace)s::Populate(')
      .Sblock('    %s) {' % self._GenerateParams(
          ('const base::Value& value', '%(name)s* out'))))

    if self._generate_error_messages:
      c.Append('DCHECK(error);')

    if type_.property_type == PropertyType.CHOICES:
      for choice in type_.choices:
        (c.Sblock('if (%s) {' % self._GenerateValueIsTypeExpression('value',
                                                                    choice))
            .Concat(self._GeneratePopulateVariableFromValue(
                choice,
                '(&value)',
                'out->as_%s' % choice.unix_name,
                'false',
                is_ptr=True))
            .Append('return true;')
          .Eblock('}')
        )
      (c.Concat(self._GenerateError(
          '"expected %s, got " +  %s' %
              (" or ".join(choice.name for choice in type_.choices),
              self._util_cc_helper.GetValueTypeString('value'))))
        .Append('return false;'))
    elif type_.property_type == PropertyType.OBJECT:
      (c.Sblock('if (!value.IsType(base::Value::TYPE_DICTIONARY)) {')
        .Concat(self._GenerateError(
          '"expected dictionary, got " + ' +
          self._util_cc_helper.GetValueTypeString('value')))
        .Append('return false;')
        .Eblock('}'))

      if type_.properties or type_.additional_properties is not None:
        c.Append('const base::DictionaryValue* dict = '
                     'static_cast<const base::DictionaryValue*>(&value);')
        if self._generate_error_messages:
            c.Append('std::set<std::string> keys;')
      for prop in type_.properties.itervalues():
        c.Concat(self._InitializePropertyToDefault(prop, 'out'))
      for prop in type_.properties.itervalues():
        if self._generate_error_messages:
          c.Append('keys.insert("%s");' % (prop.name))
        c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
      # Check for extra values.
      if self._generate_error_messages:
        (c.Sblock('for (base::DictionaryValue::Iterator it(*dict); '
                       '!it.IsAtEnd(); it.Advance()) {')
          .Sblock('if (!keys.count(it.key())) {')
          .Concat(self._GenerateError('"found unexpected key \'" + '
                                          'it.key() + "\'"'))
          .Eblock('}')
          .Eblock('}')
        )
      if type_.additional_properties is not None:
        if type_.additional_properties.property_type == PropertyType.ANY:
          c.Append('out->additional_properties.MergeDictionary(dict);')
        else:
          cpp_type = self._type_helper.GetCppType(type_.additional_properties,
                                                  is_in_container=True)
          (c.Append('for (base::DictionaryValue::Iterator it(*dict);')
            .Sblock('     !it.IsAtEnd(); it.Advance()) {')
              .Append('%s tmp;' % cpp_type)
              .Concat(self._GeneratePopulateVariableFromValue(
                  type_.additional_properties,
                  '(&it.value())',
                  'tmp',
                  'false'))
              .Append('out->additional_properties[it.key()] = tmp;')
            .Eblock('}')
          )
      c.Append('return true;')
    (c.Eblock('}')
      .Substitute({'namespace': cpp_namespace, 'name': classname}))
    return c
Ejemplo n.º 11
0
    def _GenerateType(self, type_, is_toplevel=False, generate_typedefs=False):
        """Generates a struct for |type_|.

    |is_toplevel|       implies that the type was declared in the "types" field
                        of an API schema. This determines the correct function
                        modifier(s).
    |generate_typedefs| controls whether primitive types should be generated as
                        a typedef. This may not always be desired. If false,
                        primitive types are ignored.
    """
        classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
        c = Code()

        if type_.functions:
            # Wrap functions within types in the type's namespace.
            (c.Append('namespace %s {' % classname).Append())
            for function in type_.functions.values():
                c.Cblock(self._GenerateFunction(function))
            c.Append('}  // namespace %s' % classname)
        elif type_.property_type == PropertyType.ARRAY:
            if generate_typedefs and type_.description:
                c.Comment(type_.description)
            c.Cblock(
                self._GenerateType(type_.item_type, is_toplevel=is_toplevel))
            if generate_typedefs:
                (c.Append('typedef std::vector<%s > %s;' %
                          (self._type_helper.GetCppType(
                              type_.item_type), classname)))
        elif type_.property_type == PropertyType.STRING:
            if generate_typedefs:
                if type_.description:
                    c.Comment(type_.description)
                c.Append('typedef std::string %(classname)s;')
        elif type_.property_type == PropertyType.ENUM:
            if type_.description:
                c.Comment(type_.description)
            c.Cblock(self._GenerateEnumDeclaration(classname, type_))
            # Top level enums are in a namespace scope so the methods shouldn't be
            # static. On the other hand, those declared inline (e.g. in an object) do.
            maybe_static = '' if is_toplevel else 'static '
            (c.Append().Append(
                '%sconst char* ToString(%s as_enum);' %
                (maybe_static, classname)).Append(
                    '%s%s Parse%s(const std::string& as_string);' %
                    (maybe_static, classname, classname)))
        elif type_.property_type in (PropertyType.CHOICES,
                                     PropertyType.OBJECT):
            if type_.description:
                c.Comment(type_.description)

            (c.Sblock('struct %(classname)s {').Append(
                '%(classname)s();').Append('~%(classname)s();').Append(
                    '%(classname)s(const %(classname)s&) = delete;').
             Append('%(classname)s& operator=(const %(classname)s&) = delete;'
                    ).Append('%(classname)s(%(classname)s&& rhs);').Append(
                        '%(classname)s& operator=(%(classname)s&& rhs);'))

            if type_.origin.from_manifest_keys:
                c.Append()
                c.Comment('Manifest key constants.')
                c.Concat(
                    self._GenerateManifestKeyConstants(
                        type_.properties.values()))

            if type_.origin.from_json:
                (c.Append().Comment(
                    'Populates a %s object from a base::Value. Returns'
                    ' whether |out| was successfully populated.' %
                    classname).Append('static bool Populate(%s);' %
                                      self._GenerateParams(
                                          ('const base::Value& value',
                                           '%s* out' % classname))))
                if is_toplevel:
                    (c.Append().Comment(
                        'Creates a %s object from a base::Value, or NULL on '
                        'failure.' % classname).Append(
                            'static std::unique_ptr<%s> FromValue(%s);' %
                            (classname,
                             self._GenerateParams(
                                 ('const base::Value& value', )))))
            if type_.origin.from_client:
                value_type = ('base::Value'
                              if type_.property_type is PropertyType.CHOICES
                              else 'base::DictionaryValue')
                (c.Append().Comment(
                    'Returns a new %s representing the serialized form of this '
                    '%s object.' % (value_type, classname)).Append(
                        'std::unique_ptr<%s> ToValue() const;' % value_type))

            if type_.origin.from_manifest_keys:
                c.Cblock(self._GenerateParseFromDictionary(type_, classname))

            if type_.property_type == PropertyType.CHOICES:
                # Choices are modelled with optional fields for each choice. Exactly one
                # field of the choice is guaranteed to be set by the compiler.
                c.Cblock(self._GenerateTypes(type_.choices))
                c.Append('// Choices:')
                for choice_type in type_.choices:
                    c.Append('%s as_%s;' % (self._type_helper.GetCppType(
                        choice_type, is_ptr=True), choice_type.unix_name))
            else:
                properties = type_.properties.values()
                (c.Append().Cblock(
                    self._GenerateTypes(p.type_ for p in properties)).Cblock(
                        self._GenerateFields(properties)))
                if type_.additional_properties is not None:
                    # Most additionalProperties actually have type "any", which is better
                    # modelled as a DictionaryValue rather than a map of string -> Value.
                    if type_.additional_properties.property_type == PropertyType.ANY:
                        c.Append(
                            'base::DictionaryValue additional_properties;')
                    else:
                        (c.Cblock(
                            self._GenerateType(type_.additional_properties)).
                         Append(
                             'std::map<std::string, %s> additional_properties;'
                             % self._type_helper.GetCppType(
                                 type_.additional_properties,
                                 is_in_container=True)))
            (c.Eblock('};'))
        return c.Substitute({'classname': classname})
Ejemplo n.º 12
0
  def _GenerateType(self, type_, is_toplevel=False, generate_typedefs=False):
    """Generates a struct for |type_|.

    |is_toplevel|       implies that the type was declared in the "types" field
                        of an API schema. This determines the correct function
                        modifier(s).
    |generate_typedefs| controls whether primitive types should be generated as
                        a typedef. This may not always be desired. If false,
                        primitive types are ignored.
    """
    classname = cpp_util.Classname(schema_util.StripNamespace(type_.name))
    c = Code()

    if type_.functions:
      # Wrap functions within types in the type's namespace.
      (c.Append('namespace %s {' % classname)
        .Append()
      )
      for function in type_.functions.values():
        c.Cblock(self._GenerateFunction(function))
      c.Append('}  // namespace %s' % classname)
    elif type_.property_type == PropertyType.ARRAY:
      if generate_typedefs and type_.description:
        c.Comment(type_.description)
      c.Cblock(self._GenerateType(type_.item_type))
      if generate_typedefs:
        (c.Append('typedef std::vector<%s > %s;' % (
                       self._type_helper.GetCppType(type_.item_type),
                       classname))
        )
    elif type_.property_type == PropertyType.STRING:
      if generate_typedefs:
        if type_.description:
          c.Comment(type_.description)
        c.Append('typedef std::string %(classname)s;')
    elif type_.property_type == PropertyType.ENUM:
      if type_.description:
        c.Comment(type_.description)
      c.Sblock('enum %(classname)s {')
      c.Append('%s,' % self._type_helper.GetEnumNoneValue(type_))
      for value in type_.enum_values:
        c.Append('%s,' % self._type_helper.GetEnumValue(type_, value))
      # Top level enums are in a namespace scope so the methods shouldn't be
      # static. On the other hand, those declared inline (e.g. in an object) do.
      maybe_static = '' if is_toplevel else 'static '
      (c.Eblock('};')
        .Append()
        .Append('%sstd::string ToString(%s as_enum);' %
                    (maybe_static, classname))
        .Append('%s%s Parse%s(const std::string& as_string);' %
                    (maybe_static, classname, classname))
      )
    elif type_.property_type == PropertyType.OBJECT:
      if type_.description:
        c.Comment(type_.description)
      (c.Sblock('struct %(classname)s {')
          .Append('%(classname)s();')
          .Append('~%(classname)s();')
      )
      if type_.origin.from_json:
        (c.Append()
          .Comment('Populates a %s object from a base::Value. Returns'
                   ' whether |out| was successfully populated.' % classname)
          .Append('static bool Populate(const base::Value& value, '
                  '%(classname)s* out);')
        )
      if type_.origin.from_client:
        (c.Append()
          .Comment('Returns a new base::DictionaryValue representing the'
                   ' serialized form of this %s object.' % classname)
          .Append('scoped_ptr<base::DictionaryValue> ToValue() const;')
        )
      properties = type_.properties.values()
      (c.Append()
        .Cblock(self._GenerateTypes(p.type_ for p in properties))
        .Cblock(self._GenerateFields(properties)))
      if type_.additional_properties is not None:
        # Most additionalProperties actually have type "any", which is better
        # modelled as a DictionaryValue rather than a map of string -> Value.
        if type_.additional_properties.property_type == PropertyType.ANY:
          c.Append('base::DictionaryValue additional_properties;')
        else:
          (c.Cblock(self._GenerateType(type_.additional_properties))
            .Append('std::map<std::string, %s> additional_properties;' %
                cpp_util.PadForGenerics(
                    self._type_helper.GetCppType(type_.additional_properties,
                                                 is_in_container=True)))
          )
      (c.Eblock()
        .Append()
        .Sblock(' private:')
          .Append('DISALLOW_COPY_AND_ASSIGN(%(classname)s);')
        .Eblock('};')
      )
    elif type_.property_type == PropertyType.CHOICES:
      if type_.description:
        c.Comment(type_.description)
      # Choices are modelled with optional fields for each choice. Exactly one
      # field of the choice is guaranteed to be set by the compiler.
      (c.Sblock('struct %(classname)s {')
          .Append('%(classname)s();')
          .Append('~%(classname)s();')
          .Append())
      c.Cblock(self._GenerateTypes(type_.choices))
      if type_.origin.from_json:
        (c.Comment('Populates a %s object from a base::Value. Returns'
                   ' whether |out| was successfully populated.' % classname)
          .Append('static bool Populate(const base::Value& value, '
                  '%(classname)s* out);')
          .Append()
        )
      if type_.origin.from_client:
        (c.Comment('Returns a new base::Value representing the'
                   ' serialized form of this %s object.' % classname)
          .Append('scoped_ptr<base::Value> ToValue() const;')
          .Append()
        )
      c.Append('// Choices:')
      for choice_type in type_.choices:
        c.Append('%s as_%s;' % (
            self._type_helper.GetCppType(choice_type, is_ptr=True),
            choice_type.unix_name))
      c.Eblock('};')
    c.Substitute({'classname': classname})
    return c