// Copyright 2025, Luís Murta // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include #include namespace freepipe { template struct Task { explicit constexpr Task(Args &&...args) requires(sizeof...(Args) > 0) : args_(std::forward(args)...) {} explicit constexpr Task() requires(sizeof...(Args) == 0) {} 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_); } 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 Task<>{}; } else { return Task{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) { std::apply(std::forward(func), *std::move(task)); return Task<>{}; } else { return Task{std::apply(std::forward(func), *std::move(task))}; } } template > constexpr auto operator|(Task const &task, std::basic_ostream &os) { std::apply([&os](auto &&...args) { ((os << args << '\n'), ...); }, *task); return Task<>{}; } template > constexpr auto operator|(Task &&task, std::basic_ostream &os) { std::apply([&os](auto &&...args) { ((os << args << '\n'), ...); }, *std::move(task)); return Task<>{}; } class Pipe : public Task<> {}; } // namespace freepipe