aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Herrmann <adrian.herrmann@qt.io>2024-02-28 15:41:37 +0100
committerAdrian Herrmann <adrian.herrmann@qt.io>2024-03-13 09:23:32 +0100
commitef7bb87eee9bd4469ad858f7ca15f190dbc4aaf9 (patch)
tree7894a256691164ebd0409093ba6728c1e16da989
parent52d7a31d05b1cab5780d2eb050100c3433a5fc11 (diff)
Add QIOPipe
Add an implementation for a QIODevice that can be used to work with anonymous pipes. It needs to be able to emit the bytesWritten and readyRead signals. This implementation is lifted from the qt5 source tree (qtdeclarative/tests/auto/qmlls/lifecycle) and might be added to Qt in the future, at which point it will be removed from the PySide source tree. Change-Id: Iff1208a366dad747352e7507da0818934c26aa4f Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--sources/pyside6/PySide6/QtCore/CMakeLists.txt9
-rw-r--r--sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in1
-rw-r--r--sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp141
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml1
-rw-r--r--sources/pyside6/PySide6/qiopipe.h36
-rw-r--r--sources/pyside6/libpyside/CMakeLists.txt4
-rw-r--r--sources/pyside6/tests/QtCore/qiopipe_test.py36
7 files changed, 225 insertions, 3 deletions
diff --git a/sources/pyside6/PySide6/QtCore/CMakeLists.txt b/sources/pyside6/PySide6/QtCore/CMakeLists.txt
index 3b24ec1ef..f3e4be0f9 100644
--- a/sources/pyside6/PySide6/QtCore/CMakeLists.txt
+++ b/sources/pyside6/PySide6/QtCore/CMakeLists.txt
@@ -3,12 +3,16 @@
project(QtCore)
+set(CMAKE_AUTOMOC ON)
+
set(QtCore_DROPPED_ENTRIES )
set(QtCore_static_sources
"${QtCore_SOURCE_DIR}/glue/qeasingcurve_glue.cpp"
"${QtCore_SOURCE_DIR}/glue/core_snippets.cpp"
"${QtCore_SOURCE_DIR}/glue/qtcorehelper.cpp"
+ "${QtCore_SOURCE_DIR}/glue/qiopipe.cpp"
+ "${pyside6_SOURCE_DIR}/qiopipe.h"
)
if(ENABLE_WIN)
@@ -163,6 +167,7 @@ ${QtCore_GEN_DIR}/qsystemsemaphore_wrapper.cpp
${QtCore_GEN_DIR}/qt_wrapper.cpp
${QtCore_GEN_DIR}/qtcorehelper_qgenericargumentholder_wrapper.cpp
${QtCore_GEN_DIR}/qtcorehelper_qgenericreturnargumentholder_wrapper.cpp
+${QtCore_GEN_DIR}/qtcorehelper_qiopipe_wrapper.cpp
${QtCore_GEN_DIR}/qtcorehelper_qmutexlocker_wrapper.cpp
${QtCore_GEN_DIR}/qtemporarydir_wrapper.cpp
${QtCore_GEN_DIR}/qtemporaryfile_wrapper.cpp
@@ -242,6 +247,7 @@ set(QtCore_include_dirs ${QtCore_SOURCE_DIR}
)
set(QtCore_libraries pyside6
${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
+ Qt::CorePrivate
)
create_pyside_module(NAME QtCore
@@ -281,4 +287,5 @@ if (APPLE)
endforeach()
endif()
-install(FILES ${pyside6_SOURCE_DIR}/qtcorehelper.h DESTINATION include/PySide6/QtCore/)
+install(FILES ${pyside6_SOURCE_DIR}/qtcorehelper.h ${pyside6_SOURCE_DIR}/qiopipe.h
+ DESTINATION include/PySide6/QtCore/)
diff --git a/sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in b/sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in
index 55a49bb88..8383b9ae4 100644
--- a/sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in
+++ b/sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in
@@ -1 +1,2 @@
#include <qtcorehelper.h>
+#include <qiopipe.h>
diff --git a/sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp b/sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp
new file mode 100644
index 000000000..1ff234966
--- /dev/null
+++ b/sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp
@@ -0,0 +1,141 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qiopipe.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qpointer.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtCoreHelper
+{
+
+class QPipeEndPoint : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ bool isSequential() const override;
+ qint64 bytesAvailable() const override;
+
+ void setRemoteEndPoint(QPipeEndPoint *other);
+
+protected:
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+private:
+ QByteArray m_buffer;
+ QPointer<QPipeEndPoint> m_remoteEndPoint;
+};
+
+class QIOPipePrivate final : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QIOPipe)
+public:
+ QIOPipePrivate();
+ ~QIOPipePrivate() {};
+
+ std::unique_ptr<QPipeEndPoint> end1;
+ std::unique_ptr<QPipeEndPoint> end2;
+};
+
+QIOPipe::QIOPipe(QObject *parent) : QObject(*(new QIOPipePrivate()), parent) { }
+
+bool QIOPipe::open(QIODevice::OpenMode mode)
+{
+ Q_D(QIOPipe);
+
+ if (!d->end1->open(mode))
+ return false;
+ switch (mode & QIODevice::ReadWrite) {
+ case QIODevice::WriteOnly:
+ case QIODevice::ReadOnly:
+ return d->end2->open(mode ^ QIODevice::ReadWrite);
+ default:
+ return d->end2->open(mode);
+ }
+}
+
+QIODevice *QIOPipe::end1() const
+{
+ Q_D(const QIOPipe);
+ return d->end1.get();
+}
+
+QIODevice *QIOPipe::end2() const
+{
+ Q_D(const QIOPipe);
+ return d->end2.get();
+}
+
+QIOPipePrivate::QIOPipePrivate() : end1(std::make_unique<QPipeEndPoint>()),
+ end2(std::make_unique<QPipeEndPoint>())
+{
+ end1->setRemoteEndPoint(end2.get());
+ end2->setRemoteEndPoint(end1.get());
+}
+
+bool QPipeEndPoint::isSequential() const
+{
+ return true;
+}
+
+qint64 QPipeEndPoint::bytesAvailable() const
+{
+ return m_buffer.size() + QIODevice::bytesAvailable();
+}
+
+void QPipeEndPoint::setRemoteEndPoint(QPipeEndPoint *other)
+{
+ m_remoteEndPoint = other;
+}
+
+qint64 QPipeEndPoint::readData(char *data, qint64 maxlen)
+{
+ maxlen = qMin(maxlen, static_cast<qint64>(m_buffer.size()));
+ if (maxlen <= 0)
+ return 0;
+
+ Q_ASSERT(maxlen > 0);
+ memcpy(data, m_buffer.data(), static_cast<size_t>(maxlen));
+ m_buffer = m_buffer.mid(maxlen);
+ return maxlen;
+}
+
+qint64 QPipeEndPoint::writeData(const char *data, qint64 len)
+{
+ if (!m_remoteEndPoint)
+ return -1;
+
+ if (len <= 0)
+ return 0;
+
+ QByteArray &buffer = m_remoteEndPoint->m_buffer;
+ const qint64 prevLen = buffer.size();
+ Q_ASSERT(prevLen >= 0);
+ len = qMin(len, std::numeric_limits<int>::max() - prevLen);
+
+ if (len == 0)
+ return 0;
+
+ Q_ASSERT(len > 0);
+ Q_ASSERT(prevLen + len > 0);
+ Q_ASSERT(prevLen + len <= std::numeric_limits<int>::max());
+
+ buffer.resize(prevLen + len);
+ memcpy(buffer.data() + prevLen, data, static_cast<size_t>(len));
+ Q_EMIT bytesWritten(len);
+ Q_EMIT m_remoteEndPoint->readyRead();
+ return len;
+}
+
+} // namespace QtCoreHelper
+
+QT_END_NAMESPACE
+
+#include "qiopipe.moc"
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index ca932edf2..44b8d357b 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -2472,6 +2472,7 @@
<inject-code file="../glue/qtcore.cpp" snippet="unlock"/>
</add-function>
</object-type>
+ <object-type name="QIOPipe"/>
<value-type name="QGenericArgumentHolder"/>
<value-type name="QGenericReturnArgumentHolder"/>
</namespace-type>
diff --git a/sources/pyside6/PySide6/qiopipe.h b/sources/pyside6/PySide6/qiopipe.h
new file mode 100644
index 000000000..6a325f184
--- /dev/null
+++ b/sources/pyside6/PySide6/qiopipe.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QIOPIPE_H
+#define QIOPIPE_H
+
+#include <QtCore/qiodevicebase.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+namespace QtCoreHelper
+{
+
+class QIOPipePrivate;
+class QIOPipe : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QIOPipe)
+
+public:
+ QIOPipe(QObject *parent = nullptr);
+
+ bool open(QIODeviceBase::OpenMode mode);
+
+ QIODevice *end1() const;
+ QIODevice *end2() const;
+};
+
+} // namespace QtCoreHelper
+
+QT_END_NAMESPACE
+
+#endif // QIOPIPE_H
diff --git a/sources/pyside6/libpyside/CMakeLists.txt b/sources/pyside6/libpyside/CMakeLists.txt
index e9fd0d56e..ebfe123dd 100644
--- a/sources/pyside6/libpyside/CMakeLists.txt
+++ b/sources/pyside6/libpyside/CMakeLists.txt
@@ -8,7 +8,6 @@ set(libpyside_libraries Qt::Core Qt::CorePrivate)
set(CMAKE_AUTOMOC ON)
set(libpyside_HEADERS # installed below
- pysideqslotobject_p.h
class_property.h
dynamicqmetaobject.h
feature_select.h
@@ -33,6 +32,7 @@ set(libpyside_HEADERS # installed below
pysideqhash.h
pysideqmetatype.h
pysideqobject.h
+ pysideqslotobject_p.h
pysidesignal.h
pysidesignal_p.h
pysideslot_p.h
@@ -44,7 +44,6 @@ set(libpyside_HEADERS # installed below
)
set(libpyside_SRC
- pysideqslotobject_p.cpp
class_property.cpp
dynamicqmetaobject.cpp
feature_select.cpp
@@ -53,6 +52,7 @@ set(libpyside_SRC
pysideclassdecorator.cpp
pysideclassinfo.cpp
pysideqenum.cpp
+ pysideqslotobject_p.cpp
pysidemetafunction.cpp
pysidesignal.cpp
pysideslot.cpp
diff --git a/sources/pyside6/tests/QtCore/qiopipe_test.py b/sources/pyside6/tests/QtCore/qiopipe_test.py
new file mode 100644
index 000000000..53a6ba70a
--- /dev/null
+++ b/sources/pyside6/tests/QtCore/qiopipe_test.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for the QIOPipe class'''
+
+from PySide6.QtCore import QIODevice, QIOPipe
+
+import unittest
+
+
+class QIOPipeTest(unittest.TestCase):
+ def setUp(self) -> None:
+ self.pipe = QIOPipe()
+ self.pipe.open(QIODevice.OpenModeFlag.ReadWrite)
+ return super().setUp()
+
+ def tearDown(self) -> None:
+ super().tearDown()
+
+ def ready_read_bytes_written(self):
+ received_data = self.pipe.end2().readAll().data()
+ self.assertEqual(received_data, self.data)
+
+ def test_readyRead(self):
+ self.data = b"Hello, World!"
+ self.pipe.end2().readyRead.connect(self.ready_read_bytes_written)
+ self.pipe.end1().write(self.data)
+
+ def test_bytesWritten(self):
+ self.data = b"Hello, World!"
+ self.pipe.end2().bytesWritten.connect(self.ready_read_bytes_written)
+ self.pipe.end1().write(self.data)
+
+
+if __name__ == '__main__':
+ unittest.main()