loci: factor out class metadata generation

The parsing code also needs this at compile time.
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index 1629641..fb9ba50 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -195,159 +195,165 @@
 ClassMetadata = namedtuple('ClassMetadata',
     ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
 
+class_metadata = []
+class_metadata_dict = {}
+
+def build_class_metadata():
+    for uclass in loxi_globals.unified.classes:
+        wire_length_get = 'NULL'
+        wire_length_set = 'NULL'
+        wire_type_get = 'NULL'
+        wire_type_set = 'NULL'
+
+        if uclass and not uclass.virtual and uclass.has_type_members:
+            wire_type_set = '%s_push_wire_types' % uclass.name
+
+        if uclass.is_message:
+            wire_length_get = 'of_object_message_wire_length_get'
+            wire_length_set = 'of_object_message_wire_length_set'
+        elif uclass.is_action:
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_action_wire_object_id_get'
+        elif uclass.is_instanceof('of_bsn_vport'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_bsn_vport_wire_object_id_get'
+        elif uclass.is_action_id:
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_action_id_wire_object_id_get'
+        elif uclass.is_instruction:
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_instruction_wire_object_id_get'
+        elif uclass.is_instanceof('of_instruction_id'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_instruction_id_wire_object_id_get'
+        elif uclass.is_instanceof('of_queue_prop'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_queue_prop_wire_object_id_get'
+        elif uclass.is_instanceof('of_table_feature_prop'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_table_feature_prop_wire_object_id_get'
+        elif uclass.is_instanceof('of_meter_band'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_meter_band_wire_object_id_get'
+        elif uclass.is_instanceof('of_hello_elem'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_hello_elem_wire_object_id_get'
+        elif uclass.is_instanceof('of_bsn_tlv'):
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_get = 'of_bsn_tlv_wire_object_id_get'
+        elif uclass.is_oxm:
+            wire_length_get = 'of_oxm_wire_length_get'
+            wire_type_get = 'of_oxm_wire_object_id_get'
+        elif uclass.name == "of_packet_queue":
+            wire_length_get = 'of_packet_queue_wire_length_get'
+            wire_length_set = 'of_packet_queue_wire_length_set'
+        elif uclass.name == "of_meter_stats":
+            wire_length_get = 'of_meter_stats_wire_length_get'
+            wire_length_set = 'of_meter_stats_wire_length_set'
+        elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
+                "of_flow_stats_entry", "of_bucket", "of_table_features",
+                "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
+                "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
+                "of_bsn_gentable_desc_stats_entry"]:
+            wire_length_get = "of_u16_len_wire_length_get"
+            wire_length_set = "of_u16_len_wire_length_set"
+        elif uclass.name == 'of_match_v3':
+            wire_length_set = 'of_tlv16_wire_length_set'
+            wire_length_get = 'of_tlv16_wire_length_get'
+            wire_type_set = 'of_match_v3_push_wire_types'
+
+        class_metadata.append(ClassMetadata(
+            name=uclass.name,
+            wire_length_get=wire_length_get,
+            wire_length_set=wire_length_set,
+            wire_type_get=wire_type_get,
+            wire_type_set=wire_type_set))
+
+    class_metadata.extend([
+        ClassMetadata(
+            name="of_action_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_action_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_action_id_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_action_id_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_bsn_vport_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_bsn_vport_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_instruction_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_instruction_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_instruction_id_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_instruction_id_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_queue_prop_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_queue_prop_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_table_feature_prop_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_table_feature_prop_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_meter_band_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_meter_band_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_hello_elem_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_hello_elem_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_bsn_tlv_header",
+            wire_length_set='of_tlv16_wire_length_set',
+            wire_length_get='of_tlv16_wire_length_get',
+            wire_type_get='of_bsn_tlv_wire_object_id_get',
+            wire_type_set='NULL'),
+        ClassMetadata(
+            name="of_oxm_header",
+            wire_length_set='NULL',
+            wire_length_get='of_oxm_wire_length_get',
+            wire_type_get='of_oxm_wire_object_id_get',
+            wire_type_set='NULL'),
+    ])
+
+    for metadata in class_metadata:
+        class_metadata_dict[metadata.name] = metadata
+
 def generate_class_metadata(install_dir):
     with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
         util.render_template(out, "loci_class_metadata.h")
 
     with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
-        class_metadata = []
-        for uclass in loxi_globals.unified.classes:
-            wire_length_get = 'NULL'
-            wire_length_set = 'NULL'
-            wire_type_get = 'NULL'
-            wire_type_set = 'NULL'
-
-            if uclass and not uclass.virtual and uclass.has_type_members:
-                wire_type_set = '%s_push_wire_types' % uclass.name
-
-            if uclass.is_message and uclass.name != "of_header":
-                wire_length_get = 'of_object_message_wire_length_get'
-                wire_length_set = 'of_object_message_wire_length_set'
-            elif uclass.is_action:
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_action_wire_object_id_get'
-            elif uclass.is_instanceof('of_bsn_vport'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_bsn_vport_wire_object_id_get'
-            elif uclass.is_action_id:
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_action_id_wire_object_id_get'
-            elif uclass.is_instruction:
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_instruction_wire_object_id_get'
-            elif uclass.is_instanceof('of_instruction_id'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_instruction_id_wire_object_id_get'
-            elif uclass.is_instanceof('of_queue_prop'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_queue_prop_wire_object_id_get'
-            elif uclass.is_instanceof('of_table_feature_prop'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_table_feature_prop_wire_object_id_get'
-            elif uclass.is_instanceof('of_meter_band'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_meter_band_wire_object_id_get'
-            elif uclass.is_instanceof('of_hello_elem'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_hello_elem_wire_object_id_get'
-            elif uclass.is_instanceof('of_bsn_tlv'):
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_get = 'of_bsn_tlv_wire_object_id_get'
-            elif uclass.is_oxm:
-                wire_length_get = 'of_oxm_wire_length_get'
-                wire_type_get = 'of_oxm_wire_object_id_get'
-            elif uclass.name == "of_packet_queue":
-                wire_length_get = 'of_packet_queue_wire_length_get'
-                wire_length_set = 'of_packet_queue_wire_length_set'
-            elif uclass.name == "of_meter_stats":
-                wire_length_get = 'of_meter_stats_wire_length_get'
-                wire_length_set = 'of_meter_stats_wire_length_set'
-            elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
-                   "of_flow_stats_entry", "of_bucket", "of_table_features",
-                   "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
-                   "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
-                   "of_bsn_gentable_desc_stats_entry"]:
-                wire_length_get = "of_u16_len_wire_length_get"
-                wire_length_set = "of_u16_len_wire_length_set"
-            elif uclass.name == 'of_match_v3':
-                wire_length_set = 'of_tlv16_wire_length_set'
-                wire_length_get = 'of_tlv16_wire_length_get'
-                wire_type_set = 'of_match_v3_push_wire_types'
-
-            class_metadata.append(ClassMetadata(
-                name=uclass.name,
-                wire_length_get=wire_length_get,
-                wire_length_set=wire_length_set,
-                wire_type_get=wire_type_get,
-                wire_type_set=wire_type_set))
-
-        class_metadata.extend([
-            ClassMetadata(
-                name="of_action_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_action_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_action_id_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_action_id_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_bsn_vport_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_bsn_vport_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_instruction_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_instruction_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_instruction_id_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_instruction_id_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_queue_prop_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_queue_prop_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_table_feature_prop_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_table_feature_prop_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_meter_band_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_meter_band_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_hello_elem_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_hello_elem_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_bsn_tlv_header",
-                wire_length_set='of_tlv16_wire_length_set',
-                wire_length_get='of_tlv16_wire_length_get',
-                wire_type_get='of_bsn_tlv_wire_object_id_get',
-                wire_type_set='NULL'),
-            ClassMetadata(
-                name="of_oxm_header",
-                wire_length_set='NULL',
-                wire_length_get='of_oxm_wire_length_get',
-                wire_type_get='of_oxm_wire_object_id_get',
-                wire_type_set='NULL'),
-        ])
-
         util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)
diff --git a/lang_c.py b/lang_c.py
index 8e153fe..c7b68f7 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -123,6 +123,7 @@
     for (name, fn) in targets.items():
         with template_utils.open_output(install_dir, name) as outfile:
             fn(outfile, os.path.basename(name))
+    c_gen.codegen.build_class_metadata()
     c_gen.codegen.generate_classes(install_dir)
     c_gen.codegen.generate_header_classes(install_dir)
     c_gen.codegen.generate_classes_header(install_dir)