diff --git a/src/voy/engine/asio/service.cpp b/.vim-template:qml similarity index 75% copy from src/voy/engine/asio/service.cpp copy to .vim-template:qml index b3fdd22..f372f91 100644 --- a/src/voy/engine/asio/service.cpp +++ b/.vim-template:qml @@ -1,38 +1,28 @@ /* - * Copyright (C) 2018 Ivan Čukić + * Copyright (C) %YEAR% %USER% <%MAIL%> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ -#include "service.h" +import QtQuick 2.9 -namespace voy::engine::asio { +Item { + id: root -service& service::instance() -{ - static service s_instance; - return s_instance; } -void service::run() -{ - instance().m_asio_service.run(); -} - -} // namespace voy::transport::asio - diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eb1f92..08d912e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,101 +1,101 @@ cmake_minimum_required (VERSION 3.11) project (lancelot) set (PROJECT_VERSION "0.1") set (PROJECT_VERSION_MAJOR 0) set (CMAKE_CXX_STANDARD 17) -add_definitions (-fexceptions -pthread) +add_definitions (-fexceptions -pthread -Werror=unused-result) if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message (FATAL_ERROR "This project requires an out of source build") endif () # There is no using CMake without Extra CMake Modules include (FeatureSummary) find_package (ECM 5.46 NO_MODULE) set_package_properties ( ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules" ) feature_summary (WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) # Where to search for the custom CMake modules set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} "${CMAKE_SOURCE_DIR}/cmake/modules" ) include (KDEInstallDirs) include (KDECMakeSettings) # TODO: Move deps to subfolders where they are actually needed # Qt and KF5 are needed for the UI set (REQUIRED_QT_VERSION 5.10.0) find_package ( Qt5 REQUIRED COMPONENTS Gui Qml Quick ) set (CMAKE_AUTOMOC ON) find_package ( KF5 REQUIRED COMPONENTS Service I18n Baloo Activities Config CoreAddons ) - +add_definitions(-DQT_NO_KEYWORDS) # Boost ASIO is needed for the reactive streams event processing find_package ( Boost 1.67 REQUIRED - COMPONENTS system filesystem regex # asio and process are header-only + COMPONENTS system filesystem regex thread # asio and process are header-only ) include_directories (${Boost_INCLUDE_DIR}) # Boost ASIO + ZMQ for the transport find_package ( ZMQ REQUIRED ) set_package_properties ( ZMQ PROPERTIES TYPE REQUIRED DESCRIPTION "ZeroMQ is a high-performance asynchronous messaging library" URL "http://zeromq.org/" ) include_directories (${ZMQ_INCLUDE_DIR} "3rdparty/azmq/") # Capn Proto is used for message serialization find_package ( CapnProto REQUIRED ) set_package_properties ( CapnProto PROPERTIES TYPE REQUIRED DESCRIPTION "Cap'n Proto - efficient data interchange format" URL "https://capnproto.org/" ) include_directories (${CAPNP_INCLUDE_DIR}) # Sources add_subdirectory (src) diff --git a/src/blade/CMakeLists.txt b/src/blade/CMakeLists.txt index 59076bb..0fa0578 100644 --- a/src/blade/CMakeLists.txt +++ b/src/blade/CMakeLists.txt @@ -1,42 +1,55 @@ include_directories ( ${CMAKE_CURRENT_BUILD_DIR} ) set ( BLADE_COMMON_SRCS Protocol.cpp + + ui/UiBackend.cpp + + ${VOY_SOURCES} + main.cpp ) if (NOT EXISTS "${CAPNP_EXECUTABLE}") # Workaround for some CMake problems with CapnProto set(CAPNP_EXECUTABLE "/usr/bin/capnp") set(CAPNPC_CXX_EXECUTABLE "/usr/bin/capnpc-c++") set(CAPNP_INCLUDE_DIRECTORY "/usr/include") set(CAPNP_INCLUDE_DIRS "/usr/include") endif() capnp_generate_cpp ( BLADE_CAPNP_SRCS BLADE_CAPNP_HEADERS protocol/ping_message.capnp protocol/query_message.capnp protocol/error_message.capnp protocol/controller_message.capnp ) add_executable ( bladed ${BLADE_COMMON_SRCS} ${BLADE_CAPNP_SRCS} ) target_link_libraries ( bladed + Qt5::Core + Qt5::Quick + ${capnp_LIBRARIES} + + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${Boost_THREAD_LIBRARY} ${ZMQ_LIBRARIES} - Qt5::Core + -pthread ) diff --git a/src/blade/main.cpp b/src/blade/main.cpp index 410c394..a6cd42e 100644 --- a/src/blade/main.cpp +++ b/src/blade/main.cpp @@ -1,45 +1,98 @@ /* - * Copyright (C) 2018 Ivan Čukić + * Copyright (C) 2018, 2019 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ -#include "ControllerMessage.h" +#include #include "Protocol.h" +#include "ControllerMessage.h" +#include "ui/UiBackend.h" #include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + using namespace std::literals::string_literals; +using namespace std::literals::chrono_literals; + +namespace qt = voy::qt; int main(int argc, char *argv[]) { + QGuiApplication app(argc, argv); + using blade::ControllerMessage; using blade::PingMessage; using blade::QueryMessage; ControllerMessage cm; cm.host = "Host"; cm.controller = "Cler"; cm.message = QueryMessage{ 1 , "GGG"_qs }; blade::serialize(cm); - return 0; + QQmlApplicationEngine engine; + + auto context = engine.rootContext(); + + UiBackend backend; + + context->setContextProperty("BladeUiBackend", &backend); + + engine.load(app.arguments()[1]); + + if (engine.rootObjects().isEmpty()) { + return -1; + } + + boost::thread thread([&backend] { + auto cout = [] (auto&& value) { + qDebug() << "SINK: " << value; + }; + + using voy::dsl::operator|; + + auto pipeline = + qt::signal(&backend, &UiBackend::searchRequested) | + qt::slot(&backend, &UiBackend::searchFinished); + // | voy::sink{cout}; + + voy::event_loop::run(); + }); + + return app.exec(); } diff --git a/src/voy/engine/asio/service.cpp b/src/blade/ui/UiBackend.cpp similarity index 80% copy from src/voy/engine/asio/service.cpp copy to src/blade/ui/UiBackend.cpp index b3fdd22..a8946e7 100644 --- a/src/voy/engine/asio/service.cpp +++ b/src/blade/ui/UiBackend.cpp @@ -1,38 +1,30 @@ /* * Copyright (C) 2018 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ -#include "service.h" +#include "UiBackend.h" -namespace voy::engine::asio { +#include -service& service::instance() +void UiBackend::search(const QString &query) { - static service s_instance; - return s_instance; + Q_EMIT searchRequested(query); } -void service::run() -{ - instance().m_asio_service.run(); -} - -} // namespace voy::transport::asio - diff --git a/src/voy/engine/asio/service.cpp b/src/blade/ui/UiBackend.h similarity index 75% copy from src/voy/engine/asio/service.cpp copy to src/blade/ui/UiBackend.h index b3fdd22..624af88 100644 --- a/src/voy/engine/asio/service.cpp +++ b/src/blade/ui/UiBackend.h @@ -1,38 +1,43 @@ /* * Copyright (C) 2018 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ -#include "service.h" +#ifndef BLADE_UIBACKEND_H +#define BLADE_UIBACKEND_H -namespace voy::engine::asio { +#include -service& service::instance() -{ - static service s_instance; - return s_instance; -} +class UiBackend: public QObject { + Q_OBJECT -void service::run() -{ - instance().m_asio_service.run(); -} +public Q_SLOTS: + void search(const QString &query); -} // namespace voy::transport::asio +Q_SIGNALS: + void searchRequested(const QString &query); + + void searchFinished(const QString &query); + +private: + +}; + +#endif // include guard diff --git a/src/blade/ui/window.qml b/src/blade/ui/window.qml new file mode 100644 index 0000000..49418e6 --- /dev/null +++ b/src/blade/ui/window.qml @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 Ivan Čukić + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +import QtQuick 2.9 + +import QtQuick.Window 2.2 +import QtQuick.Layouts 1.11 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + +PlasmaCore.Dialog { + id: dialog + + Component.onCompleted: { + dialog.show(); + } + + ColumnLayout { + id: root + + Layout.minimumWidth: 320 + Layout.minimumHeight: Screen.desktopAvailableHeight + + Connections { + target: BladeUiBackend + onSearchFinished: console.log("Connection valid: " + query) + } + + PlasmaComponents.TextField { + Layout.fillWidth: true + onTextChanged: BladeUiBackend.search(text) + } + + PlasmaExtras.ScrollArea { + Layout.fillWidth: true + Layout.fillHeight: true + + ListView { + delegate: PlasmaComponents.ListItem { + height: 2 * units.smallSpacing + itemTitle.height + + PlasmaComponents.Label { + id: itemTitle + anchors { + left: parent.left + top: parent.top + } + text: model.text + } + } + + model: ListModel { + ListElement { + text: "Hello" + } + ListElement { + text: "World" + } + } + } + } + } +} diff --git a/src/blade/ui/window.qmlc b/src/blade/ui/window.qmlc new file mode 100644 index 0000000..f884f47 Binary files /dev/null and b/src/blade/ui/window.qmlc differ diff --git a/src/tests/voy/CMakeLists.txt b/src/tests/voy/CMakeLists.txt index 67ed950..2bf0dc7 100644 --- a/src/tests/voy/CMakeLists.txt +++ b/src/tests/voy/CMakeLists.txt @@ -1,91 +1,98 @@ message ("Voy source dir: ${VOY_SOURCE_DIR}") message ("Voy sources: ${VOY_SOURCES}") +# Simple tests + foreach ( test_name IN ITEMS VALUES_TEST PROCESS_TEST DELAYED_TEST DELAYED_VALS_TEST FILTER_TEST SLICE_TEST MERGE_TEST TCP_TEST ZMQ_SUB_TEST ZMQ_PUB_TEST ZMQ_PUBSUB_TEST ASSOCIATIVITY_TEST ) message("This is a test: ${test_name}") add_executable ( "voy_test_${test_name}" ${VOY_SOURCES} tests_simple.cpp ) target_compile_definitions ( "voy_test_${test_name}" PUBLIC "-D${test_name}" ) target_link_libraries ( "voy_test_${test_name}" ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${ZMQ_LIBRARIES} -pthread ) endforeach() +# Multiprocess test + foreach ( test_name IN ITEMS TEST_FRONTEND TEST_BACKEND_1 TEST_BACKEND_2 ) message("This is a multiprocess test: ${test_name}") add_executable ( "voy_test_multiprocess_${test_name}" ${VOY_SOURCES} tests_multiprocess.cpp ) target_compile_definitions ( "voy_test_multiprocess_${test_name}" PUBLIC "-D${test_name}" ) target_link_libraries ( "voy_test_multiprocess_${test_name}" ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${ZMQ_LIBRARIES} -pthread ) endforeach() -# add_executable ( -# voy_test_process_1 -# tests_multiprocess.cpp -# -# engine/asio/service.cpp -# ) -# -# target_link_libraries ( -# voy_test_process_1 -# ${Boost_SYSTEM_LIBRARY} -# ${Boost_FILESYSTEM_LIBRARY} -# ${Boost_REGEX_LIBRARY} -# ${ZMQ_LIBRARIES} -# -pthread -# ) + +# Separate-thread test + +add_executable ( + "voy_test_separate_thread" + ${VOY_SOURCES} + tests_thread.cpp + ) + +target_link_libraries ( + "voy_test_separate_thread" + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${ZMQ_LIBRARIES} + -pthread + ) diff --git a/src/tests/voy/tests_thread.cpp b/src/tests/voy/tests_thread.cpp new file mode 100644 index 0000000..ae97f74 --- /dev/null +++ b/src/tests/voy/tests_thread.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Ivan Čukić + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +int main(int argc, char *argv[]) +{ + using voy::dsl::operator|; + using namespace std::literals::string_literals; + using namespace std::literals::chrono_literals; + + boost::thread thread([] { + auto cout = [] (auto&& value) { + std::cout << "Out: " << voy_fwd(value) << std::endl; + }; + + auto pipeline_delayed = + voy::delayed(5s, "I'm finally here"s) | voy::sink{cout}; + + voy::event_loop::run(); + }); + + std::cout << "Doing something\n"; + + thread.join(); + + return 0; +} + diff --git a/src/voy/basic/delayed.h b/src/voy/basic/delayed.h index c2cf3fe..d99b242 100644 --- a/src/voy/basic/delayed.h +++ b/src/voy/basic/delayed.h @@ -1,140 +1,142 @@ /* * Copyright (C) 2018 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ #ifndef VOY_BASIC_DELAYED_H #define VOY_BASIC_DELAYED_H // STL #include #include // Boost #include // Self #include "../utils.h" #include "../traits.h" #include "../dsl/node_tags.h" #include "../dsl/node_traits.h" #include "../engine/asio/service.h" namespace voy { using voy::utils::non_copyable; using voy::dsl::continuator_base, voy::dsl::source_node_tag; namespace detail { template class delayed_impl: non_copyable { voy_assert_value_type(T); public: using node_category = source_node_tag; explicit delayed_impl(std::chrono::seconds delay, std::initializer_list c) : m_delay{delay} , m_values{c} { } template explicit delayed_impl(std::chrono::seconds delay, C&& c) : m_delay{delay} , m_values{voy_fwd(c)} { } template class node: continuator_base, non_copyable { using base = continuator_base; public: using value_type = T; node(std::chrono::seconds delay, std::vector&& values, Cont&& cont) : base{std::move(cont)} , m_delay{delay} , m_values{std::move(values)} { } node(node&& other) = default; void init() { base::init(); m_delay_timer = boost::asio::steady_timer( engine::asio::service::instance(), m_delay); m_delay_timer->async_wait([this] (const boost::system::error_code& e) { for (auto&& value: m_values) { base::emit(std::move(value)); } + m_values.clear(); + base::notify_ended(); }); } private: std::chrono::seconds m_delay; std::vector m_values; std::optional m_delay_timer; }; template auto with_continuation(Cont&& cont) && { return node(m_delay, std::move(m_values), voy_fwd(cont)); } private: std::chrono::seconds m_delay; std::vector m_values; }; } // namespace detail template decltype(auto) delayed(std::chrono::seconds delay, T&& value) { return detail::delayed_impl(delay, {voy_fwd(value)}); } template decltype(auto) delayed_values(std::chrono::seconds delay, T&& values) { return detail::delayed_impl(delay, voy_fwd(values)); } template decltype(auto) delayed_values(std::chrono::seconds delay, std::initializer_list values) { return detail::delayed_impl(delay, std::move(values)); } } // namespace voy #endif // include guard diff --git a/src/voy/dsl.h b/src/voy/dsl.h index 3aa1c86..3e73303 100644 --- a/src/voy/dsl.h +++ b/src/voy/dsl.h @@ -1,275 +1,275 @@ /* * Copyright (C) 2018 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ #ifndef VOY_DSL_H #define VOY_DSL_H // STL #include #include // Self #include "utils.h" #include "dsl/node_tags.h" #include "dsl/node_traits.h" #include "engine/event_loop.h" namespace voy::dsl { using node_traits::is_connection_expr, node_traits::is_node, node_traits::is_source, node_traits::is_sink, node_traits::node_category, node_traits::has_with_continuation; // We need to be able to store the connected graph paths (pipelines) // inside of ordinary classes, so we will return a type-erased pipeline // to the caller once the path is complete class pipeline { public: virtual ~pipeline() {} virtual void init() = 0; using ptr = std::unique_ptr; }; namespace detail { // The actual type of a pipeline template struct pipeline_impl: pipeline { explicit pipeline_impl(T&& content) noexcept : node{std::move(content.node)} { } void init() override { node.init(); } T node; }; // In order to use the fold expressions, we need to provide an operator // on which to fold. We can create a wrapper type with operator<< // defined for it template struct node_wrapper: utils::non_copyable { voy_assert_value_type(Node); node_wrapper(Node node) : node{std::move(node)} { } node_wrapper(node_wrapper&& other) = delete; void operator=(node_wrapper&&) = delete; void init() { node.init(); } Node node; }; template auto make_node_wrapper(Node&& node) { voy_assert_value_type(Node); return node_wrapper{std::move(node)}; } template decltype(auto) operator<< (node_wrapper&& receiver, node_wrapper&& sender) { voy_assert_value_type(Left); voy_assert_value_type(Right); return make_node_wrapper( std::move(sender.node).with_continuation(std::move(receiver.node)) ); } // Goes through all the items in a tuple, and connects one by one template pipeline::ptr connect_all(std::tuple items, std::index_sequence) { return std::make_unique< decltype(pipeline_impl((... << make_node_wrapper(std::get(std::move(items)))))) > ((... << make_node_wrapper(std::get(std::move(items))))); } // The connection_expr class represents one pipe operation // in the AST where the left and right arguments can be either // compound expressions themselves, or single nodes template struct connection_expr { voy_assert_value_type(LeftGraph); voy_assert_value_type(RightGraph); LeftGraph left; RightGraph right; // An expression is also a graph node using node_category = NodeCategory; // ... but we still need to be able to differentiate it from normal nodes using connection_expr_tag = node_category; // Generates a tuple of all nodes in an expression from right to left, // that is, from the sink to the source auto collect_graph_nodes() { auto collect_left_graph_nodes = [this] { if constexpr (is_connection_expr) { return left.collect_graph_nodes(); } else { return std::make_tuple(std::move(left)); } }; auto collect_right_graph_nodes = [this] { if constexpr (is_connection_expr) { return right.collect_graph_nodes(); } else { return std::make_tuple(std::move(right)); } }; return std::tuple_cat(collect_right_graph_nodes(), collect_left_graph_nodes()); } connection_expr(LeftGraph left, RightGraph right) : left{std::move(left)} , right{std::move(right)} { } auto evaluate() { if constexpr (std::is_same_v) { auto sink_to_source_items = collect_graph_nodes(); auto result = connect_all(std::move(sink_to_source_items), std::make_index_sequence< std::tuple_size_v< std::decay_t > >()); voy::event_loop::invoke_later([result = result.get()] { result->init(); }); return result; } else { voy_fail(node_category, "'evaluate' can only be called on a complete path"); } } }; template < typename NodeCategory , typename LeftGraph , typename RightGraph > auto make_connection_expr(LeftGraph&& left, RightGraph&& right) { return connection_expr < NodeCategory , traits::remove_cvref_t , traits::remove_cvref_t > { voy_fwd(left), voy_fwd(right) }; } template < typename Left , typename Right , typename LeftVal = traits::remove_cvref_t , typename RightVal = traits::remove_cvref_t > decltype(auto) connect_streams(Left&& left, Right&& right) { static_assert(is_node, "The left needs to be a node"); static_assert(is_node, "The right needs to be a node"); static_assert( is_connection_expr || has_with_continuation, "The left node needs to be a connection expression, or to have with_continuation member function"); #define MAKE(Type) \ make_connection_expr(std::move(left), \ std::move(right)) if constexpr (!is_source && !is_sink) { return MAKE(transformation_node_tag); } else if constexpr (is_source && !is_sink) { return MAKE(node_category); } else if constexpr (!is_source && is_sink) { return MAKE(node_category); } else { // If we have both a sink and a source, we can connect the // nodes in this path of the graph return MAKE(void).evaluate(); } #undef MAKE } } // namespace detail template < typename Left , typename Right , voy_require( is_node && is_node ) > -decltype(auto) operator| (Left&& left, Right&& right) +[[nodiscard]] decltype(auto) operator| (Left&& left, Right&& right) { return detail::connect_streams(voy_fwd(left), voy_fwd(right)); } } // namespace voy::dsl #endif // include guard diff --git a/src/voy/engine/asio/service.cpp b/src/voy/engine/asio/service.cpp index b3fdd22..bc450ae 100644 --- a/src/voy/engine/asio/service.cpp +++ b/src/voy/engine/asio/service.cpp @@ -1,38 +1,38 @@ /* * Copyright (C) 2018 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ #include "service.h" namespace voy::engine::asio { service& service::instance() { static service s_instance; return s_instance; } void service::run() { - instance().m_asio_service.run(); + m_asio_service.run(); } } // namespace voy::transport::asio diff --git a/src/voy/wrappers/qt/connect.h b/src/voy/wrappers/qt/connect.h new file mode 100644 index 0000000..a405b1f --- /dev/null +++ b/src/voy/wrappers/qt/connect.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2019 Ivan Čukić + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +#ifndef VOY_WRAPPERS_QT_CONNECT_H +#define VOY_WRAPPERS_QT_CONNECT_H + +// STL +#include + +// Qt +#include +#include +#include + +// Self +#include "../../utils.h" +#include "../../traits.h" +#include "../../dsl/node_tags.h" + +namespace voy::qt { + +using voy::utils::non_copyable; + +using voy::dsl::continuator_base, + voy::dsl::source_node_tag; + +namespace detail { + + template + class signal_impl: non_copyable { + voy_assert_value_type(T); + + public: + using node_category = source_node_tag; + + explicit signal_impl(Object* sender, Signal signal) + : m_sender{sender} + , m_signal{std::move(signal)} + { + } + + template + class node: public continuator_base, non_copyable { + using base = continuator_base; + + public: + node(Object* sender, Signal signal, Cont cont) + : base{std::move(cont)} + , m_sender{sender} + , m_signal{std::move(signal)} + { + } + + void init() + { + qDebug() << "Calling init"; + base::init(); + + if constexpr (std::is_same_v) { + m_connection = QObject::connect( + m_sender, m_signal, + [this] (auto value) { + // TODO: This needs to be async + base::emit(std::move(value)); + }); + } else { + m_connection = QObject::connect( + m_sender, m_signal, + [this] (T value) { + // TODO: This needs to be async + base::emit(std::move(value)); + }); + } + + QObject::connect( + m_sender, &QObject::destroyed, + [this] { + base::notify_ended(); + }); + } + + private: + QMetaObject::Connection m_connection; + Object* m_sender; + Signal m_signal; + }; + + + template + auto with_continuation(Cont&& cont) && + { + return node(m_sender, std::move(m_signal), voy_fwd(cont)); + } + + private: + Object* m_sender; + Signal m_signal; + + }; + + + + template + class slot_impl: non_copyable { + public: + using node_category = sink_node_tag; + + explicit slot_impl(Object* object, Slot slot) + : m_receiver(object) + , m_slot(slot) + { + } + + template + void operator() (T&& value) const + { + std::invoke(m_slot, m_receiver, voy_fwd(value)); + } + + void init() + { + } + + void notify_ended() const + { + } + + private: + Object* m_receiver; + Slot m_slot; + }; + + +} // namespace detail + + +template +auto signal(Object* sender, Signal&& signal) +{ + return detail::signal_impl(sender, voy_fwd(signal)); +} + + +template +auto slot(Object* receiver, Slot&& slot) +{ + return detail::slot_impl(receiver, voy_fwd(slot)); +} + +} // namespace voy + +#endif // include guard +