// Copyright 2025, Luís Murta // SPDX-License-Identifier: MIT #pragma once #include #include #include // #include #include #include #include #include #include namespace freepipe { template struct Task { explicit constexpr Task(std::shared_ptr ioc, Args &&...args) requires(sizeof...(Args) > 0) : ioc_(std::move(ioc)), args_(std::forward(args)...) {} explicit constexpr Task(std::shared_ptr ioc) requires(sizeof...(Args) == 0) : ioc_(std::move(ioc)) {} constexpr auto const &operator*() const & { return args_; } constexpr auto &operator*() & { return args_; } constexpr auto &&operator*() && { return std::move(args_); } constexpr auto const &&operator*() const && { return std::move(args_); } std::shared_ptr ioc_; private: std::tuple args_; }; template F> constexpr auto operator|(Task const &task, F &&func) { using R = std::invoke_result_t; if constexpr (std::is_void_v) { std::apply(std::forward(func), *task); return boost::asio::post(task.ioc_, Task<>{task.ioc_}); } else { return Task{task.ioc_, std::apply(std::forward(func), *task)}; } } template F> constexpr auto operator|(Task &&task, F &&func) { using R = std::invoke_result_t; if constexpr (std::is_void_v) { boost::asio::post(*task.ioc_, [&] { std::apply(std::forward(func), std::move(*task)); }); return Task<>{task.ioc_}; } else { return Task{task.ioc_, std::apply(std::forward(func), std::move(*task))}; } } template ... F> constexpr auto operator|(Task const &task, std::tuple &&func) { std::tuple...> ret; auto l = [&](auto &&f) { using R = std::invoke_result_t; if constexpr (std::is_void_v) { std::apply(std::forward(f), *task); return; } else { return std::apply(std::forward(f), *task); } }; std::apply(l, func); return std::make_from_tuple(std::apply( [&](F &&...f) { return Task...>( l(std::forward(f), std::index_sequence{})...); }, std::move(func))); // ( // [&] { // using R = std::invoke_result_t; // if constexpr (std::is_void_v) { // std::apply(std::forward(func), *task); // } else { // std::get(ret) = std::apply(std::forward(func), *task); // } // }(), // ...); // auto ans = std::apply( // [](auto &&f) { // return Task( // if constexpr (std::is_void_v) { return Task<>{}; } else { // return Task{f}; // }, // f...); // }, // std::move(func)); // return std::make_from_tuple(std::move(ret)); } template ... F> constexpr auto operator|(Task &&task, std::tuple &&func) { std::tuple...> ret; ( [&] { using R = std::invoke_result_t; if constexpr (std::is_void_v) { std::apply(std::forward(func), *std::move(task)); } else { std::get(ret) = std::apply(std::forward(func), *std::move(task)); } }(), ...); return std::make_from_tuple(std::move(ret)); } template > constexpr auto operator|(Task const &task, std::basic_ostream &os) { std::apply([&os](auto &&...args) { ((os << args << '\n'), ...); }, *task); return Task<>{task.ioc_}; } template > constexpr auto operator|(Task &&task, std::basic_ostream &os) { std::apply([&os](auto &&...args) { ((os << args << '\n'), ...); }, std::move(*task)); return Task<>{task.ioc_}; } class Pipe : public Task<> { // std::shared_ptr io_context_; public: Pipe() : Task<>(std::make_shared()) {} explicit Pipe(std::shared_ptr io_context) : Task<>{io_context} {} }; } // namespace freepipe