Don't make all object and enum types (de)serializable by default.
Detect this from the input file instead.
---
src/esx/esx_vi_generator.py | 167 +++++++++++++++++++++++++++++++-----------
1 files changed, 123 insertions(+), 44 deletions(-)
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 0c1c9e0..8ac1249 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -73,6 +73,14 @@ class Parameter:
return self.type in predefined_enums or self.type in enums_by_name
+ def is_object(self):
+ return self.type in predefined_objects or self.type in objects_by_name
+
+
+ def is_type_generated(self):
+ return self.type in enums_by_name or self.type in objects_by_name
+
+
def generate_parameter(self, is_last = False, is_header = True, offset = 0):
if self.occurrence == OCCURRENCE__IGNORED:
raise ValueError("invalid function parameter occurrence value
'%s'" % self.occurrence)
@@ -275,6 +283,14 @@ class Property:
return self.type in predefined_enums or self.type in enums_by_name
+ def is_object(self):
+ return self.type in predefined_objects or self.type in objects_by_name
+
+
+ def is_type_generated(self):
+ return self.type in enums_by_name or self.type in objects_by_name
+
+
def generate_struct_member(self):
if self.occurrence == OCCURRENCE__IGNORED:
return " /* FIXME: %s is currently ignored */\n" % self.name
@@ -427,11 +443,10 @@ class Object(Base):
FEATURE__SERIALIZE = (1 << 5)
FEATURE__DESERIALIZE = (1 << 6)
-
def __init__(self, name, extends, properties, features = 0, extended_by = None):
Base.__init__(self, "struct", name)
self.extends = extends
- self.features = features | Object.FEATURE__SERIALIZE |
Object.FEATURE__DESERIALIZE
+ self.features = features
self.properties = properties
self.extended_by = extended_by
@@ -1191,7 +1206,7 @@ class Enum(Base):
def __init__(self, name, values, features=0):
Base.__init__(self, "enum", name)
self.values = values
- self.features = features | Enum.FEATURE__SERIALIZE | Enum.FEATURE__DESERIALIZE
+ self.features = features
def generate_header(self):
@@ -1372,20 +1387,6 @@ def parse_method(block):
-def inherit_features(obj):
- if obj.extended_by is not None:
- for extended_by in obj.extended_by:
- objects_by_name[extended_by].features |= obj.features
-
- if obj.extends is not None:
- objects_by_name[obj.extends].features |= obj.features
-
- if obj.extended_by is not None:
- for extended_by in obj.extended_by:
- inherit_features(objects_by_name[extended_by])
-
-
-
def is_known_type(type):
return type in predefined_objects or \
type in predefined_enums or \
@@ -1422,12 +1423,10 @@ predefined_objects = ["AnyType",
"MethodFault",
"ManagedObjectReference"]
-
additional_enum_features = { "ManagedEntityStatus" :
Enum.FEATURE__ANY_TYPE,
"TaskInfoState" :
Enum.FEATURE__ANY_TYPE,
"VirtualMachinePowerState" :
Enum.FEATURE__ANY_TYPE }
-
additional_object_features = { "AutoStartDefaults" :
Object.FEATURE__ANY_TYPE,
"AutoStartPowerInfo" :
Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
"DatastoreHostMount" :
Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
@@ -1446,24 +1445,16 @@ additional_object_features = { "AutoStartDefaults"
: Object.FEATURE__AN
"PropertyFilterSpec" :
Object.FEATURE__LIST,
"ResourcePoolResourceUsage" :
Object.FEATURE__ANY_TYPE,
"SelectionSpec" :
Object.FEATURE__DYNAMIC_CAST,
+ "ServiceContent" :
Object.FEATURE__DESERIALIZE,
"SharesInfo" :
Object.FEATURE__ANY_TYPE,
"TaskInfo" :
Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
"UserSession" :
Object.FEATURE__ANY_TYPE,
"VirtualDiskSpec" :
Object.FEATURE__DYNAMIC_CAST,
"VirtualMachineQuestionInfo" :
Object.FEATURE__ANY_TYPE,
- "VirtualMachineSnapshotTree" :
Object.FEATURE__DEEP_COPY | Object.FEATURE__ANY_TYPE }
-
+ "VirtualMachineSnapshotTree" :
Object.FEATURE__DEEP_COPY | Object.FEATURE__ANY_TYPE,
+ "VmEventArgument" :
Object.FEATURE__DESERIALIZE }
-removed_object_features = { "DynamicProperty" :
Object.FEATURE__SERIALIZE,
- "LocalizedMethodFault" :
Object.FEATURE__SERIALIZE,
- "ObjectContent" :
Object.FEATURE__SERIALIZE,
- "ObjectUpdate" :
Object.FEATURE__SERIALIZE,
- "PropertyChange" :
Object.FEATURE__SERIALIZE,
- "PropertyFilterUpdate" :
Object.FEATURE__SERIALIZE,
- "TaskInfo" :
Object.FEATURE__SERIALIZE,
- "UpdateSet" :
Object.FEATURE__SERIALIZE,
- "VirtualMachineConfigInfo" :
Object.FEATURE__SERIALIZE,
- "VirtualMachineSnapshotTree" :
Object.FEATURE__SERIALIZE }
+removed_object_features = {}
@@ -1499,6 +1490,7 @@ block = None
+# parse input file
for line in file(input_filename, "rb").readlines():
number += 1
@@ -1538,11 +1530,34 @@ for line in file(input_filename, "rb").readlines():
+for method in methods_by_name.values():
+ # method parameter types must be serializable
+ for parameter in method.parameters:
+ if not parameter.is_type_generated():
+ continue
+
+ if parameter.is_enum():
+ enums_by_name[parameter.type].features |= Enum.FEATURE__SERIALIZE
+ else:
+ objects_by_name[parameter.type].features |= Object.FEATURE__SERIALIZE
+
+ # method return types must be deserializable
+ if method.returns and method.returns.is_type_generated():
+ if method.returns.is_enum():
+ enums_by_name[method.returns.type].features |= Enum.FEATURE__DESERIALIZE
+ else:
+ objects_by_name[method.returns.type].features |= Object.FEATURE__DESERIALIZE
+
+
+
for enum in enums_by_name.values():
# apply additional features
if enum.name in additional_enum_features:
enum.features |= additional_enum_features[enum.name]
+ if additional_enum_features[enum.name] & Enum.FEATURE__ANY_TYPE:
+ enum.features |= Enum.FEATURE__DESERIALIZE
+
for obj in objects_by_name.values():
@@ -1566,17 +1581,12 @@ for obj in objects_by_name.values():
if obj.name in additional_object_features:
obj.features |= additional_object_features[obj.name]
+ if additional_object_features[obj.name] & Object.FEATURE__ANY_TYPE:
+ obj.features |= Object.FEATURE__DESERIALIZE
+
if obj.name in removed_object_features:
obj.features &= ~removed_object_features[obj.name]
- # spread deep copy onto properties
- if obj.features & Object.FEATURE__DEEP_COPY:
- for property in obj.properties:
- if property.occurrence != OCCURRENCE__IGNORED and \
- property.type not in predefined_objects and \
- property.type in objects_by_name:
- objects_by_name[property.type].features |= Object.FEATURE__DEEP_COPY
-
# detect extended_by relation
if obj.extends is not None:
extended_obj = objects_by_name[obj.extends]
@@ -1589,6 +1599,80 @@ for obj in objects_by_name.values():
+def propagate_feature(obj, feature):
+ global features_have_changed
+
+ if not (obj.features & feature):
+ return
+
+ for property in obj.properties:
+ if property.occurrence == OCCURRENCE__IGNORED or \
+ not property.is_type_generated():
+ continue
+
+ if property.is_enum():
+ if feature == Object.FEATURE__SERIALIZE and \
+ not (enums_by_name[property.type].features &
Enum.FEATURE__SERIALIZE):
+ enums_by_name[property.type].features |= Enum.FEATURE__SERIALIZE
+ features_have_changed = True
+ elif feature == Object.FEATURE__DESERIALIZE and \
+ not (enums_by_name[property.type].features &
Enum.FEATURE__DESERIALIZE):
+ enums_by_name[property.type].features |= Enum.FEATURE__DESERIALIZE
+ features_have_changed = True
+ elif property.is_object():
+ if not (objects_by_name[property.type].features & feature):
+ objects_by_name[property.type].features |= feature
+ features_have_changed = True
+
+ if obj.name != property.type:
+ propagate_feature(objects_by_name[property.type], feature)
+
+
+
+def inherit_features(obj):
+ global features_have_changed
+
+ if obj.extended_by is not None:
+ for extended_by in obj.extended_by:
+ previous = objects_by_name[extended_by].features
+ objects_by_name[extended_by].features |= obj.features
+
+ if objects_by_name[extended_by].features != previous:
+ features_have_changed = True
+
+ if obj.extends is not None:
+ previous = objects_by_name[obj.extends].features
+ objects_by_name[obj.extends].features |= obj.features
+
+ if objects_by_name[obj.extends].features != previous:
+ features_have_changed = True
+
+ if obj.extended_by is not None:
+ for extended_by in obj.extended_by:
+ inherit_features(objects_by_name[extended_by])
+
+
+
+# there are two directions to spread features:
+# 1) up and down the inheritance chain
+# 2) from object types to their member property types
+# spreading needs to be done alternating on both directions because they can
+# affect each other
+features_have_changed = True
+
+while features_have_changed:
+ features_have_changed = False
+
+ for obj in objects_by_name.values():
+ propagate_feature(obj, Object.FEATURE__DEEP_COPY)
+ propagate_feature(obj, Object.FEATURE__SERIALIZE)
+ propagate_feature(obj, Object.FEATURE__DESERIALIZE)
+
+ for obj in objects_by_name.values():
+ inherit_features(obj)
+
+
+
for obj in managed_objects_by_name.values():
for property in obj.properties:
if property.occurrence != OCCURRENCE__IGNORED and \
@@ -1611,11 +1695,6 @@ for obj in managed_objects_by_name.values():
-for obj in objects_by_name.values():
- inherit_features(obj)
-
-
-
types_typedef.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
types_typeenum.write("/* Generated by esx_vi_generator.py */\n\n")
types_typetostring.write("/* Generated by esx_vi_generator.py */\n\n")
--
1.7.0.4