aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h')
-rw-r--r--sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h87
1 files changed, 87 insertions, 0 deletions
diff --git a/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h b/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
new file mode 100644
index 000000000..7b6abc54b
--- /dev/null
+++ b/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2025 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDE_CAPSULEMETHOD_P_H
+#define PYSIDE_CAPSULEMETHOD_P_H
+
+#include <sbkpython.h>
+
+extern "C"
+{
+
+/**
+ * This code is needed to solve, in C++ and adhering to the stable API,
+ * creating what are in effect lambda functions as instance methods on custom
+ * types. The goal is to be able to add methods to a dynamic type. If the .rep
+ * file defines a slot `mySlot`, it need to be added to the dynamic type. For
+ * Source types, this should be an abstract method that raises a
+ * NotImplementedError unless defined in the Python subclass. For Replica
+ * types, this should include an implementation that forwards the request
+ * through the underlying QRemoteObjectReplica instance.
+ *
+ * The stable API doesn't currently provide a way define a method that can
+ * receive both the `self`, `args`, and runtime (but constant per method, i.e.,
+ * lambda like) data using Py_tp_methods. Possibly post 3.13 when METH_METHOD is
+ * part of the stable API. But for now, it is not.
+ *
+ * The solution is to create a custom descriptor
+ * (https://docs.python.org/3/howto/descriptor.html) that can hold the runtime
+ * data and then when called, will return a PyCFunction_New generated PyObject
+ * that is passed both class instance `self` and the runtime data (a PyCapsule)
+ * together as a tuple as a new `self` for the method. The static method
+ * definition needs to expect and handle this, but when combined in C++, we can
+ * define a single handler that receives both the original `self` of the instance
+ * and the runtime capsule with data for handling.
+ */
+
+/**
+ * The CapsuleDescriptorData struct is what will be passed as the pseudo `self`
+ * from a CapsuleMethod or CapsuleProperty to the associated handler method. The
+ * handler method (which should look like a standard PyMethodDef method) should
+ * parse it into the payload (the "lambda variables") and the actual instance
+ * (the "self").
+ */
+struct CapsuleDescriptorData
+{
+ PyObject *self;
+ PyObject *payload;
+};
+
+/**
+ * The new type defining a descriptor that stores a PyCapsule. This is used to
+ * store the runtime data, with the __get__ method returning a new Callable.
+ */
+PyTypeObject *CapsuleMethod_TypeF(void);
+
+/**
+ * The new type defining a descriptor that stores a PyCapsule. This is used to
+ * store the runtime data, with the __get__ (and __set__ if isWritable) providing
+ * property behavior.
+ */
+PyTypeObject *CapsuleProperty_TypeF(bool isWritable);
+
+/**
+ * Add a capsule method (a descriptor) to a type. This will create a new capsule
+ * method descriptor and add it as an attribute to the type, using the given name.
+ *
+ * A single handle can then respond to what appear to be distinct methods on the
+ * type, but using the runtime data (from the capsule) when handling each call.
+ *
+ * @param type The type to attach the created descriptor to.
+ * @param method The method definition to associate with the descriptor.
+ * The name of the method will be used as the attribute name.
+ * @param capsule The capsule to store in the descriptor.
+ * @return True if the descriptor was added successfully, false otherwise.
+ */
+bool add_capsule_method_to_type(PyTypeObject *type, PyMethodDef *method,
+ PyObject *capsule);
+
+/**
+ * Make a new CapsuleProperty type.
+ */
+PyObject *make_capsule_property(PyMethodDef *method, PyObject *capsule,
+ bool isWritable = false);
+
+} // extern "C"
+
+#endif // PYSIDE_CAPSULEMETHOD_P_H