def _GenerateListValueToEnumArrayConversion(self, item_type, src_var, dst_var, failure_value, is_ptr=False): """Returns Code that converts a ListValue of string constants from |src_var| into an array of enums of |type_| in |dst_var|. On failure, returns |failure_value|. """ c = Code() accessor = '.' if is_ptr: accessor = '->' cpp_type = self._type_helper.GetCppType(item_type, is_in_container=True) c.Append('%s.reset(new std::vector<%s>);' % (dst_var, cpp_util.PadForGenerics(cpp_type))) (c.Sblock('for (const auto& it : *(%s)) {' % src_var) .Append('%s tmp;' % self._type_helper.GetCppType(item_type)) .Concat(self._GenerateStringToEnumConversion(item_type, '(it)', 'tmp', failure_value)) .Append('%s%spush_back(tmp);' % (dst_var, accessor)) .Eblock('}') ) return c
def _GenerateObjectTypeToValue(self, cpp_namespace, type_): """Generates a function that serializes an object-representing type into a base::DictionaryValue. """ c = Code() (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' % cpp_namespace) .Append('scoped_ptr<base::DictionaryValue> value(' 'new base::DictionaryValue());') .Append() ) for prop in type_.properties.values(): if prop.optional: # Optional enum values are generated with a NONE enum value. underlying_type = self._type_helper.FollowRef(prop.type_) if underlying_type.property_type == PropertyType.ENUM: c.Sblock('if (%s != %s) {' % (prop.unix_name, self._type_helper.GetEnumNoneValue(prop.type_))) else: c.Sblock('if (%s.get()) {' % prop.unix_name) # ANY is a base::Value which is abstract and cannot be a direct member, so # it will always be a pointer. is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY c.Append('value->SetWithoutPathExpansion("%s", %s);' % ( prop.name, self._CreateValueFromType(prop.type_, 'this->%s' % prop.unix_name, is_ptr=is_ptr))) if prop.optional: c.Eblock('}') if type_.additional_properties is not None: if type_.additional_properties.property_type == PropertyType.ANY: c.Append('value->MergeDictionary(&additional_properties);') else: # Non-copyable types will be wrapped in a linked_ptr for inclusion in # maps, so we need to unwrap them. needs_unwrap = ( not self._type_helper.IsCopyable(type_.additional_properties)) cpp_type = self._type_helper.GetCppType(type_.additional_properties, is_in_container=True) (c.Sblock('for (std::map<std::string, %s>::const_iterator it =' % cpp_util.PadForGenerics(cpp_type)) .Append(' additional_properties.begin();') .Append(' it != additional_properties.end(); ++it) {') .Append('value->SetWithoutPathExpansion(it->first, %s);' % self._CreateValueFromType( type_.additional_properties, '%sit->second' % ('*' if needs_unwrap else ''))) .Eblock('}') ) return (c.Append() .Append('return value.Pass();') .Eblock('}'))
def GetCppType(self, type_, is_ptr=False, is_in_container=False): """Translates a model.Property or model.Type into its C++ type. If REF types from different namespaces are referenced, will resolve using self._schema_loader. Use |is_ptr| if the type is optional. This will wrap the type in a scoped_ptr if possible (it is not possible to wrap an enum). Use |is_in_container| if the type is appearing in a collection, e.g. a std::vector or std::map. This will wrap it in the correct type with spacing. """ cpp_type = None if type_.property_type == PropertyType.REF: ref_type = self._FindType(type_.ref_type) if ref_type is None: raise KeyError('Cannot find referenced type: %s' % type_.ref_type) cpp_type = self.GetCppType(ref_type) elif type_.property_type == PropertyType.BOOLEAN: cpp_type = 'bool' elif type_.property_type == PropertyType.INTEGER: cpp_type = 'int' elif type_.property_type == PropertyType.INT64: cpp_type = 'int64' elif type_.property_type == PropertyType.DOUBLE: cpp_type = 'double' elif type_.property_type == PropertyType.STRING: cpp_type = 'std::string' elif type_.property_type in (PropertyType.ENUM, PropertyType.OBJECT, PropertyType.CHOICES): if self._default_namespace is type_.namespace: cpp_type = cpp_util.Classname(type_.name) else: cpp_namespace = cpp_util.GetCppNamespace( type_.namespace.environment.namespace_pattern, type_.namespace.unix_name) cpp_type = '%s::%s' % (cpp_namespace, cpp_util.Classname(type_.name)) elif type_.property_type == PropertyType.ANY: cpp_type = 'base::Value' elif type_.property_type == PropertyType.FUNCTION: # Functions come into the json schema compiler as empty objects. We can # record these as empty DictionaryValues so that we know if the function # was passed in or not. cpp_type = 'base::DictionaryValue' elif type_.property_type == PropertyType.ARRAY: item_cpp_type = self.GetCppType(type_.item_type, is_in_container=True) cpp_type = 'std::vector<%s>' % cpp_util.PadForGenerics( item_cpp_type) elif type_.property_type == PropertyType.BINARY: cpp_type = 'std::vector<char>' else: raise NotImplementedError('Cannot get type of %s' % type_.property_type) # HACK: optional ENUM is represented elsewhere with a _NONE value, so it # never needs to be wrapped in pointer shenanigans. # TODO(kalman): change this - but it's an exceedingly far-reaching change. if not self.FollowRef(type_).property_type == PropertyType.ENUM: if is_in_container and (is_ptr or not self.IsCopyable(type_)): cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type) elif is_ptr: cpp_type = 'scoped_ptr<%s>' % cpp_util.PadForGenerics(cpp_type) return cpp_type
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( '%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 in (PropertyType.CHOICES, 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(%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 scoped_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( 'scoped_ptr<%s> ToValue() const;' % value_type)) 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;' % 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('};')) return c.Substitute({'classname': classname})