blob: 5dd8d08e0398352965c1a5b5701d651d3af73f18 [file] [log] [blame]
Patrick Williamsf79f3582016-10-09 16:12:26 -05001from .namedelement import NamedElement
Patrick Williams52dd41e2016-10-14 18:41:27 -05002from .renderer import Renderer
Patrick Williamsd0cd9662016-11-14 21:55:07 -06003import yaml
Patrick Williamsf79f3582016-10-09 16:12:26 -05004
Patrick Williamsf5c3cde2016-10-21 11:49:01 -05005
Patrick Williams52dd41e2016-10-14 18:41:27 -05006class Property(NamedElement, Renderer):
Patrick Williamsf79f3582016-10-09 16:12:26 -05007 def __init__(self, **kwargs):
Patrick Williams18b29ba2020-01-24 16:09:06 -06008 self.enum = False
Patrick Williamsf79f3582016-10-09 16:12:26 -05009 self.typeName = kwargs.pop('type', None)
Patrick Williamsd0cd9662016-11-14 21:55:07 -060010 self.cppTypeName = self.parse_cpp_type(self.typeName)
Patrick Williamsf79f3582016-10-09 16:12:26 -050011 self.defaultValue = kwargs.pop('default', None)
Adriana Kobylak69425eb2018-08-17 13:55:19 -050012 self.flags = kwargs.pop('flags', [])
Adriana Kobylak75a2e252018-06-06 10:49:24 -050013 self.errors = kwargs.pop('errors', [])
Patrick Williamsf79f3582016-10-09 16:12:26 -050014
Matthew Barthf0dd3b52019-02-07 11:08:15 -060015 if (self.defaultValue is not None):
16 if (isinstance(self.defaultValue, bool)):
17 # Convert True/False to 'true'/'false'
18 # because it will be rendered as C++ code
19 self.defaultValue = 'true' if self.defaultValue else 'false'
20 elif(isinstance(self.defaultValue, str) and
21 self.typeName.lower() == "string"):
22 # Wrap string type default values with double-quotes
23 self.defaultValue = "\"" + self.defaultValue + "\""
Lei YU4d741892019-01-14 09:59:10 +080024
Patrick Williamsf79f3582016-10-09 16:12:26 -050025 super(Property, self).__init__(**kwargs)
Patrick Williams62c3f272016-10-09 16:21:34 -050026
Patrick Williams2adcefa2016-11-16 08:23:12 -060027 def is_enum(self):
Patrick Williams18b29ba2020-01-24 16:09:06 -060028 return self.enum
Patrick Williams2adcefa2016-11-16 08:23:12 -060029
Patrick Williams0aa0dde2016-11-16 08:14:33 -060030 """ Return a conversion of the cppTypeName valid as a function parameter.
31 Currently only 'enum' requires conversion.
32 """
33 def cppTypeParam(self, interface, server=True):
Patrick Williams2adcefa2016-11-16 08:23:12 -060034 if self.is_enum():
Patrick Williams18b29ba2020-01-24 16:09:06 -060035 r = self.cppTypeName
Patrick Williams0aa0dde2016-11-16 08:14:33 -060036 # self. means local type.
37 if r.startswith("self."):
38 return r.split('self.')[1]
39
40 r = r.split('.')
41 r.insert(-2, "server" if server else "client")
42 r = "::".join(r)
43 return r
44 return self.cppTypeName
45
46 """ Return a conversion of the cppTypeName valid as it is read out of a
47 message. Currently only 'enum' requires conversion.
48 """
49 def cppTypeMessage(self, interface):
Patrick Williams2adcefa2016-11-16 08:23:12 -060050 if self.is_enum():
Patrick Williams0aa0dde2016-11-16 08:14:33 -060051 return "std::string"
52 return self.cppTypeName
53
Patrick Williams0ad505c2016-11-16 16:17:02 -060054 def enum_namespace(self, interface):
55 if not self.is_enum():
56 return ""
57 l = self.cppTypeParam(interface).split("::")[0:-1]
58 if len(l) != 0:
59 return "::".join(l) + "::"
60 return ""
61
62 def enum_name(self, interface):
63 if not self.is_enum():
64 return ""
65 return self.cppTypeParam(interface).split("::")[-1]
66
Patrick Williamsd0cd9662016-11-14 21:55:07 -060067 def parse_cpp_type(self, typeName):
68 if not typeName:
69 return None
70
71 """ typeNames are _almost_ valid YAML. Insert a , before each [
72 and then wrap it in a [ ] and it becomes valid YAML. (assuming
73 the user gave us a valid typename)
74 """
Christian Andersene4163982016-12-09 11:24:03 +010075 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
76 typeTuple = self.__preprocess_yaml_type_array(typeArray).pop(0)
Patrick Williams18b29ba2020-01-24 16:09:06 -060077 return self.__parse_cpp_type__(typeTuple, top_type=True)
Christian Andersene4163982016-12-09 11:24:03 +010078
79 """ Take a list of dbus types from YAML and convert it to a recursive data
80 structure. Each entry of the original list gets converted into a tuple
81 consisting of the type name and a list with the params for this type,
82 e.g.
83 ['dict', ['string', 'dict', ['string', 'int64']]]
84 is converted to
Patrick Williams3f67eed2016-12-12 12:22:03 -060085 [('dict', [('string', []), ('dict', [('string', []),
86 ('int64', [])]]]
Christian Andersene4163982016-12-09 11:24:03 +010087 """
88 def __preprocess_yaml_type_array(self, typeArray):
89 result = []
90
91 for i in range(len(typeArray)):
92 # Ignore lists because we merge them with the previous element
93 if type(typeArray[i]) is list:
94 continue
95
Patrick Williams3f67eed2016-12-12 12:22:03 -060096 # If there is a next element and it is a list, merge it with the
97 # current element.
Christian Andersene4163982016-12-09 11:24:03 +010098 if i < len(typeArray)-1 and type(typeArray[i+1]) is list:
Patrick Williams3f67eed2016-12-12 12:22:03 -060099 result.append(
100 (typeArray[i],
101 self.__preprocess_yaml_type_array(typeArray[i+1])))
Christian Andersene4163982016-12-09 11:24:03 +0100102 else:
103 result.append((typeArray[i], []))
104
105 return result
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600106
107 """ Take a list of dbus types and perform validity checking, such as:
108 [ variant [ dict [ int32, int32 ], double ] ]
109 This function then converts the type-list into a C++ type string.
110 """
Patrick Williams18b29ba2020-01-24 16:09:06 -0600111 def __parse_cpp_type__(self, typeTuple, top_type=False):
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600112 propertyMap = {
113 'byte': {'cppName': 'uint8_t', 'params': 0},
114 'boolean': {'cppName': 'bool', 'params': 0},
115 'int16': {'cppName': 'int16_t', 'params': 0},
116 'uint16': {'cppName': 'uint16_t', 'params': 0},
117 'int32': {'cppName': 'int32_t', 'params': 0},
118 'uint32': {'cppName': 'uint32_t', 'params': 0},
119 'int64': {'cppName': 'int64_t', 'params': 0},
120 'uint64': {'cppName': 'uint64_t', 'params': 0},
121 'double': {'cppName': 'double', 'params': 0},
Waqar Hameed596a2232018-10-05 15:42:20 +0200122 'unixfd': {'cppName': 'sdbusplus::message::unix_fd', 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600123 'string': {'cppName': 'std::string', 'params': 0},
Patrick Williams8a30a8f2017-01-06 16:29:05 -0600124 'path': {'cppName': 'sdbusplus::message::object_path',
125 'params': 0},
126 'signature': {'cppName': 'sdbusplus::message::signature',
127 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600128 'array': {'cppName': 'std::vector', 'params': 1},
129 'struct': {'cppName': 'std::tuple', 'params': -1},
William A. Kennington III4274c112018-11-26 09:50:13 -0800130 'variant': {'cppName': 'std::variant', 'params': -1},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600131 'dict': {'cppName': 'std::map', 'params': 2},
Patrick Williams18b29ba2020-01-24 16:09:06 -0600132 'enum': {'cppName': 'enum', 'params': 1}}
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600133
Christian Andersene4163982016-12-09 11:24:03 +0100134 if len(typeTuple) != 2:
135 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
136
137 first = typeTuple[0]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600138 entry = propertyMap[first]
139
140 result = entry['cppName']
141
142 # Handle 0-entry parameter lists.
143 if (entry['params'] == 0):
Christian Andersene4163982016-12-09 11:24:03 +0100144 if (len(typeTuple[1]) != 0):
145 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600146 else:
147 return result
148
Christian Andersene4163982016-12-09 11:24:03 +0100149 # Get the parameter list
150 rest = typeTuple[1]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600151
152 # Confirm parameter count matches.
153 if (entry['params'] != -1) and (entry['params'] != len(rest)):
154 raise RuntimeError("Invalid entry count for %s : %s" %
155 (first, rest))
156
Patrick Williams18b29ba2020-01-24 16:09:06 -0600157 # Switch enum for proper type.
158 if result == 'enum':
159 if top_type:
160 self.enum = True
161 return rest[0][0]
162
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600163 # Parse each parameter entry, if appropriate, and create C++ template
164 # syntax.
165 result += '<'
Patrick Williams18b29ba2020-01-24 16:09:06 -0600166 result += ", ".join(map(lambda e: self.__parse_cpp_type__(e),
167 rest))
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600168 result += '>'
169
170 return result
171
Patrick Williams62c3f272016-10-09 16:21:34 -0500172 def markdown(self, loader):
Patrick Williamse70f0e82016-10-14 22:24:17 -0500173 return self.render(loader, "property.mako.md", property=self,
Patrick Williamsf5c3cde2016-10-21 11:49:01 -0500174 post=str.strip)
Adriana Kobylakee6ac692018-06-06 09:36:51 -0500175
176 def cpp_prototype(self, loader, interface, ptype):
177 return self.render(loader, "property.mako.prototype.hpp", property=self,
178 interface=interface, ptype=ptype, post=str.rstrip)