Jelajahi Sumber

loader: add LoaderFileTypeRegistry.unregister_type()

rdb 6 tahun lalu
induk
melakukan
f63b3a86b9

+ 35 - 0
panda/src/pgraph/loaderFileTypeRegistry.cxx

@@ -113,6 +113,41 @@ register_deferred_type(const string &extension, const string &library) {
   _deferred_types[dcextension] = library;
 }
 
+/**
+ * Removes a type previously registered using register_type.
+ */
+void LoaderFileTypeRegistry::
+unregister_type(LoaderFileType *type) {
+  Types::iterator it = find(_types.begin(), _types.end(), type);
+  if (it == _types.end()) {
+    if (loader_cat.is_debug()) {
+      loader_cat.debug()
+        << "Attempt to unregister LoaderFileType " << type->get_name()
+        << " (" << type->get_type() << "), which was not registered.\n";
+    }
+    return;
+  }
+
+  _types.erase(it);
+
+  {
+    std::string dcextension = downcase(type->get_extension());
+    Extensions::iterator ei = _extensions.find(dcextension);
+    if (ei != _extensions.end() && ei->second == type) {
+      _extensions.erase(ei);
+    }
+  }
+
+  vector_string words;
+  extract_words(type->get_additional_extensions(), words);
+  for (const std::string &word : words) {
+    Extensions::iterator ei = _extensions.find(downcase(word));
+    if (ei != _extensions.end() && ei->second == type) {
+      _extensions.erase(ei);
+    }
+  }
+}
+
 /**
  * Returns the total number of types registered.
  */

+ 4 - 0
panda/src/pgraph/loaderFileTypeRegistry.h

@@ -35,10 +35,14 @@ public:
   void register_type(LoaderFileType *type);
   void register_deferred_type(const std::string &extension, const std::string &library);
 
+  void unregister_type(LoaderFileType *type);
+
 PUBLISHED:
   EXTENSION(void register_type(PyObject *type));
   EXTENSION(void register_deferred_type(PyObject *entry_point));
 
+  EXTENSION(void unregister_type(PyObject *type));
+
   int get_num_types() const;
   LoaderFileType *get_type(int n) const;
   MAKE_SEQ(get_types, get_num_types, get_type);

+ 48 - 0
panda/src/pgraph/loaderFileTypeRegistry_ext.cxx

@@ -17,6 +17,8 @@
 
 #include "pythonLoaderFileType.h"
 
+extern struct Dtool_PyTypedObject Dtool_LoaderFileType;
+
 /**
  * Registers a loader file type that is implemented in Python.
  */
@@ -64,4 +66,50 @@ register_deferred_type(PyObject *entry_point) {
   _this->register_type(loader);
 }
 
+/**
+ * If the given loader type is registered, unregisters it.
+ */
+void Extension<LoaderFileTypeRegistry>::
+unregister_type(PyObject *type) {
+  // Are we passing in a C++ file type object?
+  LoaderFileType *extracted_type;
+  if (DtoolInstance_GetPointer(type, extracted_type, Dtool_LoaderFileType)) {
+    _this->unregister_type(extracted_type);
+    return;
+  }
+
+  // If not, we may be passing in a Python file type.
+  PyObject *load_func = PyObject_GetAttrString(type, "load_file");
+  PyObject *save_func = PyObject_GetAttrString(type, "save_file");
+  PyErr_Clear();
+
+  if (load_func == nullptr && save_func == nullptr) {
+    Dtool_Raise_TypeError("expected loader type");
+    return;
+  }
+
+  // Keep looping until we've removed all instances of it.
+  bool found_any;
+  do {
+    found_any = false;
+    size_t num_types = _this->get_num_types();
+    for (size_t i = 0; i < num_types; ++i) {
+      LoaderFileType *type = _this->get_type(i);
+      if (type->is_of_type(PythonLoaderFileType::get_class_type())) {
+        PythonLoaderFileType *python_type = (PythonLoaderFileType *)type;
+        if (python_type->_load_func == load_func &&
+            python_type->_save_func == save_func) {
+          _this->unregister_type(python_type);
+          delete python_type;
+          found_any = true;
+          break;
+        }
+      }
+    }
+  } while (found_any);
+
+  Py_XDECREF(load_func);
+  Py_XDECREF(save_func);
+}
+
 #endif

+ 2 - 0
panda/src/pgraph/loaderFileTypeRegistry_ext.h

@@ -31,6 +31,8 @@ class Extension<LoaderFileTypeRegistry> : public ExtensionBase<LoaderFileTypeReg
 public:
   void register_type(PyObject *type);
   void register_deferred_type(PyObject *entry_point);
+
+  void unregister_type(PyObject *type);
 };
 
 #endif  // HAVE_PYTHON

+ 3 - 0
panda/src/pgraph/pythonLoaderFileType.h

@@ -19,6 +19,7 @@
 #ifdef HAVE_PYTHON
 
 #include "loaderFileType.h"
+#include "extension.h"
 
 /**
  * This defines a Python-based loader plug-in.  An instance of this can be
@@ -57,6 +58,8 @@ private:
   PyObject *_save_func = nullptr;
   bool _supports_compressed = false;
 
+  friend class Extension<LoaderFileTypeRegistry>;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;