blob: e412b6041ff5c5ce6c167e2099887f7d82d1fdeb [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 Williams7eb0d252020-03-13 14:33:34 -05007
8 LOCAL_ENUM_MAGIC = "<LOCAL_ENUM>"
9 NONLOCAL_ENUM_MAGIC = "<NONLOCAL_ENUM>"
10
Patrick Williamsf79f3582016-10-09 16:12:26 -050011 def __init__(self, **kwargs):
Patrick Williams18b29ba2020-01-24 16:09:06 -060012 self.enum = False
Patrick Williamsf79f3582016-10-09 16:12:26 -050013 self.typeName = kwargs.pop('type', None)
Patrick Williamsd0cd9662016-11-14 21:55:07 -060014 self.cppTypeName = self.parse_cpp_type(self.typeName)
Patrick Williamsf79f3582016-10-09 16:12:26 -050015 self.defaultValue = kwargs.pop('default', None)
Adriana Kobylak69425eb2018-08-17 13:55:19 -050016 self.flags = kwargs.pop('flags', [])
Waqar Hameed20255a52020-06-04 12:38:48 +020017 self.cpp_flags = self.or_cpp_flags(self.flags)
Adriana Kobylak75a2e252018-06-06 10:49:24 -050018 self.errors = kwargs.pop('errors', [])
Patrick Williamsf79f3582016-10-09 16:12:26 -050019
Matthew Barthf0dd3b52019-02-07 11:08:15 -060020 if (self.defaultValue is not None):
21 if (isinstance(self.defaultValue, bool)):
22 # Convert True/False to 'true'/'false'
23 # because it will be rendered as C++ code
24 self.defaultValue = 'true' if self.defaultValue else 'false'
25 elif(isinstance(self.defaultValue, str) and
26 self.typeName.lower() == "string"):
27 # Wrap string type default values with double-quotes
28 self.defaultValue = "\"" + self.defaultValue + "\""
Lei YU4d741892019-01-14 09:59:10 +080029
Patrick Williamsf79f3582016-10-09 16:12:26 -050030 super(Property, self).__init__(**kwargs)
Patrick Williams62c3f272016-10-09 16:21:34 -050031
Patrick Williams2adcefa2016-11-16 08:23:12 -060032 def is_enum(self):
Patrick Williams18b29ba2020-01-24 16:09:06 -060033 return self.enum
Patrick Williams2adcefa2016-11-16 08:23:12 -060034
Patrick Williams0aa0dde2016-11-16 08:14:33 -060035 """ Return a conversion of the cppTypeName valid as a function parameter.
36 Currently only 'enum' requires conversion.
37 """
Patrick Williamsf7e21592020-01-24 15:43:08 -060038 def cppTypeParam(self, interface, full=False, server=True):
Patrick Williams7eb0d252020-03-13 14:33:34 -050039
40 ns_type = "server" if server else "client"
41
42 iface = interface.split(".")
43 iface.insert(-1, ns_type)
44 iface = "::".join(iface)
45
Patrick Williamsa163b172020-01-24 16:34:02 -060046 r = self.cppTypeName
Patrick Williams0aa0dde2016-11-16 08:14:33 -060047
Patrick Williams7eb0d252020-03-13 14:33:34 -050048 # Fix up local enum placeholders.
49 if full:
50 r = r.replace(self.LOCAL_ENUM_MAGIC, iface)
51 else:
52 r = r.replace(self.LOCAL_ENUM_MAGIC + "::", "")
53
54 # Fix up non-local enum placeholders.
55 r = r.replace(self.NONLOCAL_ENUM_MAGIC, ns_type)
Patrick Williamsa163b172020-01-24 16:34:02 -060056
57 return r
Patrick Williams0aa0dde2016-11-16 08:14:33 -060058
Patrick Williams0ad505c2016-11-16 16:17:02 -060059 def enum_namespace(self, interface):
60 if not self.is_enum():
61 return ""
62 l = self.cppTypeParam(interface).split("::")[0:-1]
63 if len(l) != 0:
64 return "::".join(l) + "::"
65 return ""
66
67 def enum_name(self, interface):
68 if not self.is_enum():
69 return ""
70 return self.cppTypeParam(interface).split("::")[-1]
71
Patrick Williamsd0cd9662016-11-14 21:55:07 -060072 def parse_cpp_type(self, typeName):
73 if not typeName:
74 return None
75
76 """ typeNames are _almost_ valid YAML. Insert a , before each [
77 and then wrap it in a [ ] and it becomes valid YAML. (assuming
78 the user gave us a valid typename)
79 """
Christian Andersene4163982016-12-09 11:24:03 +010080 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
81 typeTuple = self.__preprocess_yaml_type_array(typeArray).pop(0)
Patrick Williams18b29ba2020-01-24 16:09:06 -060082 return self.__parse_cpp_type__(typeTuple, top_type=True)
Christian Andersene4163982016-12-09 11:24:03 +010083
84 """ Take a list of dbus types from YAML and convert it to a recursive data
85 structure. Each entry of the original list gets converted into a tuple
86 consisting of the type name and a list with the params for this type,
87 e.g.
88 ['dict', ['string', 'dict', ['string', 'int64']]]
89 is converted to
Patrick Williams3f67eed2016-12-12 12:22:03 -060090 [('dict', [('string', []), ('dict', [('string', []),
91 ('int64', [])]]]
Christian Andersene4163982016-12-09 11:24:03 +010092 """
93 def __preprocess_yaml_type_array(self, typeArray):
94 result = []
95
96 for i in range(len(typeArray)):
97 # Ignore lists because we merge them with the previous element
98 if type(typeArray[i]) is list:
99 continue
100
Patrick Williams3f67eed2016-12-12 12:22:03 -0600101 # If there is a next element and it is a list, merge it with the
102 # current element.
Christian Andersene4163982016-12-09 11:24:03 +0100103 if i < len(typeArray)-1 and type(typeArray[i+1]) is list:
Patrick Williams3f67eed2016-12-12 12:22:03 -0600104 result.append(
105 (typeArray[i],
106 self.__preprocess_yaml_type_array(typeArray[i+1])))
Christian Andersene4163982016-12-09 11:24:03 +0100107 else:
108 result.append((typeArray[i], []))
109
110 return result
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600111
112 """ Take a list of dbus types and perform validity checking, such as:
113 [ variant [ dict [ int32, int32 ], double ] ]
114 This function then converts the type-list into a C++ type string.
115 """
Patrick Williams18b29ba2020-01-24 16:09:06 -0600116 def __parse_cpp_type__(self, typeTuple, top_type=False):
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600117 propertyMap = {
118 'byte': {'cppName': 'uint8_t', 'params': 0},
119 'boolean': {'cppName': 'bool', 'params': 0},
120 'int16': {'cppName': 'int16_t', 'params': 0},
121 'uint16': {'cppName': 'uint16_t', 'params': 0},
122 'int32': {'cppName': 'int32_t', 'params': 0},
123 'uint32': {'cppName': 'uint32_t', 'params': 0},
124 'int64': {'cppName': 'int64_t', 'params': 0},
125 'uint64': {'cppName': 'uint64_t', 'params': 0},
126 'double': {'cppName': 'double', 'params': 0},
Waqar Hameed596a2232018-10-05 15:42:20 +0200127 'unixfd': {'cppName': 'sdbusplus::message::unix_fd', 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600128 'string': {'cppName': 'std::string', 'params': 0},
Patrick Williams8a30a8f2017-01-06 16:29:05 -0600129 'path': {'cppName': 'sdbusplus::message::object_path',
130 'params': 0},
131 'signature': {'cppName': 'sdbusplus::message::signature',
132 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600133 'array': {'cppName': 'std::vector', 'params': 1},
Patrick Williamsb98bdc62020-06-16 16:15:40 -0500134 'set': {'cppName': 'std::set', 'params': 1},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600135 'struct': {'cppName': 'std::tuple', 'params': -1},
William A. Kennington III4274c112018-11-26 09:50:13 -0800136 'variant': {'cppName': 'std::variant', 'params': -1},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600137 'dict': {'cppName': 'std::map', 'params': 2},
Patrick Williams18b29ba2020-01-24 16:09:06 -0600138 'enum': {'cppName': 'enum', 'params': 1}}
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600139
Christian Andersene4163982016-12-09 11:24:03 +0100140 if len(typeTuple) != 2:
141 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
142
143 first = typeTuple[0]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600144 entry = propertyMap[first]
145
146 result = entry['cppName']
147
148 # Handle 0-entry parameter lists.
149 if (entry['params'] == 0):
Christian Andersene4163982016-12-09 11:24:03 +0100150 if (len(typeTuple[1]) != 0):
151 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600152 else:
153 return result
154
Christian Andersene4163982016-12-09 11:24:03 +0100155 # Get the parameter list
156 rest = typeTuple[1]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600157
158 # Confirm parameter count matches.
159 if (entry['params'] != -1) and (entry['params'] != len(rest)):
160 raise RuntimeError("Invalid entry count for %s : %s" %
161 (first, rest))
162
Patrick Williams18b29ba2020-01-24 16:09:06 -0600163 # Switch enum for proper type.
164 if result == 'enum':
165 if top_type:
166 self.enum = True
Patrick Williamsa163b172020-01-24 16:34:02 -0600167 result = rest[0][0]
168
169 # self. means local type.
170 if result.startswith("self."):
Patrick Williams7eb0d252020-03-13 14:33:34 -0500171 return result.replace("self.", self.LOCAL_ENUM_MAGIC + "::")
172
173 # Insert place-holder for header-type namespace (ex. "server")
174 result = result.split('.')
175 result.insert(-2, self.NONLOCAL_ENUM_MAGIC)
176 result = "::".join(result)
Patrick Williamsa163b172020-01-24 16:34:02 -0600177 return result
Patrick Williams18b29ba2020-01-24 16:09:06 -0600178
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600179 # Parse each parameter entry, if appropriate, and create C++ template
180 # syntax.
181 result += '<'
Waqar Hameed67c79b02020-02-19 23:25:14 +0100182 result += ", ".join([self.__parse_cpp_type__(e) for e in rest])
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600183 result += '>'
184
185 return result
186
Patrick Williams62c3f272016-10-09 16:21:34 -0500187 def markdown(self, loader):
Patrick Williams56216242020-05-21 15:33:50 -0500188 return self.render(loader, "property.md.mako", property=self,
Patrick Williamsf5c3cde2016-10-21 11:49:01 -0500189 post=str.strip)
Adriana Kobylakee6ac692018-06-06 09:36:51 -0500190
191 def cpp_prototype(self, loader, interface, ptype):
Patrick Williams56216242020-05-21 15:33:50 -0500192 return self.render(loader, "property.prototype.hpp.mako", property=self,
Adriana Kobylakee6ac692018-06-06 09:36:51 -0500193 interface=interface, ptype=ptype, post=str.rstrip)
Waqar Hameed20255a52020-06-04 12:38:48 +0200194
195 def or_cpp_flags(self, flags):
196 """Return the corresponding ORed cpp flags."""
197 flags_dict = {
Waqar Hameed20255a52020-06-04 12:38:48 +0200198 "const": "vtable::property_::const_",
Patrick Williamse1c73d32020-07-10 16:02:27 -0500199 "deprecated": "vtable::common_::deprecated",
Waqar Hameed20255a52020-06-04 12:38:48 +0200200 "emits_change": "vtable::property_::emits_change",
201 "emits_invalidation": "vtable::property_::emits_invalidation",
Patrick Williamse1c73d32020-07-10 16:02:27 -0500202 "explicit": "vtable::property_::explicit_",
203 "hidden": "vtable::common_::hidden",
204 "readonly": False,
205 "unprivileged": "vtable::common_::unprivileged",
206 }
Waqar Hameed20255a52020-06-04 12:38:48 +0200207
208 cpp_flags = []
209 for flag in flags:
210 try:
Patrick Williamse1c73d32020-07-10 16:02:27 -0500211 if flags_dict[flag]:
212 cpp_flags.append(flags_dict[flag])
Waqar Hameed20255a52020-06-04 12:38:48 +0200213 except KeyError:
214 raise ValueError("Invalid flag \"{}\"".format(flag))
215
216 return " | ".join(cpp_flags)