diff options
| author | Adrian Herrmann <adrian.herrmann@qt.io> | 2024-02-28 15:41:37 +0100 |
|---|---|---|
| committer | Adrian Herrmann <adrian.herrmann@qt.io> | 2024-03-13 09:23:32 +0100 |
| commit | ef7bb87eee9bd4469ad858f7ca15f190dbc4aaf9 (patch) | |
| tree | 7894a256691164ebd0409093ba6728c1e16da989 | |
| parent | 52d7a31d05b1cab5780d2eb050100c3433a5fc11 (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.txt | 9 | ||||
| -rw-r--r-- | sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in | 1 | ||||
| -rw-r--r-- | sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp | 141 | ||||
| -rw-r--r-- | sources/pyside6/PySide6/QtCore/typesystem_core_common.xml | 1 | ||||
| -rw-r--r-- | sources/pyside6/PySide6/qiopipe.h | 36 | ||||
| -rw-r--r-- | sources/pyside6/libpyside/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | sources/pyside6/tests/QtCore/qiopipe_test.py | 36 |
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() |
