blob: 4349186e779209625b652c30ba7f25039396f8bb [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 Williamsa163b172020-01-24 16:34:02 -060034 r = self.cppTypeName
Patrick Williams0aa0dde2016-11-16 08:14:33 -060035
Patrick Williamsa163b172020-01-24 16:34:02 -060036 if self.is_enum():
37 if "." in r:
38 r = r.split('.')
39 r.insert(-2, "server" if server else "client")
40 r = "::".join(r)
41
42 return r
Patrick Williams0aa0dde2016-11-16 08:14:33 -060043
44 """ Return a conversion of the cppTypeName valid as it is read out of a
45 message. Currently only 'enum' requires conversion.
46 """
47 def cppTypeMessage(self, interface):
Patrick Williams2adcefa2016-11-16 08:23:12 -060048 if self.is_enum():
Patrick Williams0aa0dde2016-11-16 08:14:33 -060049 return "std::string"
50 return self.cppTypeName
51
Patrick Williams0ad505c2016-11-16 16:17:02 -060052 def enum_namespace(self, interface):
53 if not self.is_enum():
54 return ""
55 l = self.cppTypeParam(interface).split("::")[0:-1]
56 if len(l) != 0:
57 return "::".join(l) + "::"
58 return ""
59
60 def enum_name(self, interface):
61 if not self.is_enum():
62 return ""
63 return self.cppTypeParam(interface).split("::")[-1]
64
Patrick Williamsd0cd9662016-11-14 21:55:07 -060065 def parse_cpp_type(self, typeName):
66 if not typeName:
67 return None
68
69 """ typeNames are _almost_ valid YAML. Insert a , before each [
70 and then wrap it in a [ ] and it becomes valid YAML. (assuming
71 the user gave us a valid typename)
72 """
Christian Andersene4163982016-12-09 11:24:03 +010073 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
74 typeTuple = self.__preprocess_yaml_type_array(typeArray).pop(0)
Patrick Williams18b29ba2020-01-24 16:09:06 -060075 return self.__parse_cpp_type__(typeTuple, top_type=True)
Christian Andersene4163982016-12-09 11:24:03 +010076
77 """ Take a list of dbus types from YAML and convert it to a recursive data
78 structure. Each entry of the original list gets converted into a tuple
79 consisting of the type name and a list with the params for this type,
80 e.g.
81 ['dict', ['string', 'dict', ['string', 'int64']]]
82 is converted to
Patrick Williams3f67eed2016-12-12 12:22:03 -060083 [('dict', [('string', []), ('dict', [('string', []),
84 ('int64', [])]]]
Christian Andersene4163982016-12-09 11:24:03 +010085 """
86 def __preprocess_yaml_type_array(self, typeArray):
87 result = []
88
89 for i in range(len(typeArray)):
90 # Ignore lists because we merge them with the previous element
91 if type(typeArray[i]) is list:
92 continue
93
Patrick Williams3f67eed2016-12-12 12:22:03 -060094 # If there is a next element and it is a list, merge it with the
95 # current element.
Christian Andersene4163982016-12-09 11:24:03 +010096 if i < len(typeArray)-1 and type(typeArray[i+1]) is list:
Patrick Williams3f67eed2016-12-12 12:22:03 -060097 result.append(
98 (typeArray[i],
99 self.__preprocess_yaml_type_array(typeArray[i+1])))
Christian Andersene4163982016-12-09 11:24:03 +0100100 else:
101 result.append((typeArray[i], []))
102
103 return result
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600104
105 """ Take a list of dbus types and perform validity checking, such as:
106 [ variant [ dict [ int32, int32 ], double ] ]
107 This function then converts the type-list into a C++ type string.
108 """
Patrick Williams18b29ba2020-01-24 16:09:06 -0600109 def __parse_cpp_type__(self, typeTuple, top_type=False):
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600110 propertyMap = {
111 'byte': {'cppName': 'uint8_t', 'params': 0},
112 'boolean': {'cppName': 'bool', 'params': 0},
113 'int16': {'cppName': 'int16_t', 'params': 0},
114 'uint16': {'cppName': 'uint16_t', 'params': 0},
115 'int32': {'cppName': 'int32_t', 'params': 0},
116 'uint32': {'cppName': 'uint32_t', 'params': 0},
117 'int64': {'cppName': 'int64_t', 'params': 0},
118 'uint64': {'cppName': 'uint64_t', 'params': 0},
119 'double': {'cppName': 'double', 'params': 0},
Waqar Hameed596a2232018-10-05 15:42:20 +0200120 'unixfd': {'cppName': 'sdbusplus::message::unix_fd', 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600121 'string': {'cppName': 'std::string', 'params': 0},
Patrick Williams8a30a8f2017-01-06 16:29:05 -0600122 'path': {'cppName': 'sdbusplus::message::object_path',
123 'params': 0},
124 'signature': {'cppName': 'sdbusplus::message::signature',
125 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600126 'array': {'cppName': 'std::vector', 'params': 1},
127 'struct': {'cppName': 'std::tuple', 'params': -1},
William A. Kennington III4274c112018-11-26 09:50:13 -0800128 'variant': {'cppName': 'std::variant', 'params': -1},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600129 'dict': {'cppName': 'std::map', 'params': 2},
Patrick Williams18b29ba2020-01-24 16:09:06 -0600130 'enum': {'cppName': 'enum', 'params': 1}}
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600131
Christian Andersene4163982016-12-09 11:24:03 +0100132 if len(typeTuple) != 2:
133 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
134
135 first = typeTuple[0]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600136 entry = propertyMap[first]
137
138 result = entry['cppName']
139
140 # Handle 0-entry parameter lists.
141 if (entry['params'] == 0):
Christian Andersene4163982016-12-09 11:24:03 +0100142 if (len(typeTuple[1]) != 0):
143 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600144 else:
145 return result
146
Christian Andersene4163982016-12-09 11:24:03 +0100147 # Get the parameter list
148 rest = typeTuple[1]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600149
150 # Confirm parameter count matches.
151 if (entry['params'] != -1) and (entry['params'] != len(rest)):
152 raise RuntimeError("Invalid entry count for %s : %s" %
153 (first, rest))
154
Patrick Williams18b29ba2020-01-24 16:09:06 -0600155 # Switch enum for proper type.
156 if result == 'enum':
157 if top_type:
158 self.enum = True
Patrick Williamsa163b172020-01-24 16:34:02 -0600159 result = rest[0][0]
160
161 # self. means local type.
162 if result.startswith("self."):
163 return result[5:] # "self." is 5 characters
164 return result
Patrick Williams18b29ba2020-01-24 16:09:06 -0600165
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600166 # Parse each parameter entry, if appropriate, and create C++ template
167 # syntax.
168 result += '<'
Patrick Williams18b29ba2020-01-24 16:09:06 -0600169 result += ", ".join(map(lambda e: self.__parse_cpp_type__(e),
170 rest))
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600171 result += '>'
172
173 return result
174
Patrick Williams62c3f272016-10-09 16:21:34 -0500175 def markdown(self, loader):
Patrick Williamse70f0e82016-10-14 22:24:17 -0500176 return self.render(loader, "property.mako.md", property=self,
Patrick Williamsf5c3cde2016-10-21 11:49:01 -0500177 post=str.strip)
Adriana Kobylakee6ac692018-06-06 09:36:51 -0500178
179 def cpp_prototype(self, loader, interface, ptype):
180 return self.render(loader, "property.mako.prototype.hpp", property=self,
181 interface=interface, ptype=ptype, post=str.rstrip)