2727namespace kphp ::component {
2828
2929class stream {
30+ bool m_non_blocking{false };
3031 k2::descriptor m_descriptor{k2::INVALID_PLATFORM_DESCRIPTOR };
3132 kphp::coro::io_scheduler& m_scheduler{kphp::coro::io_scheduler::get ()};
3233
3334 explicit stream (k2::descriptor descriptor) noexcept
3435 : m_descriptor(descriptor) {}
3536
37+ auto read_non_blocking (std::span<std::byte> buf) const noexcept -> std::expected<size_t, int32_t>;
38+ auto write_non_blocking (std::span<const std::byte> buf) const noexcept -> std::expected<size_t, int32_t>;
39+
3640public:
3741 stream (stream&& other) noexcept
3842 : m_descriptor(std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR )) {}
@@ -60,6 +64,7 @@ class stream {
6064 auto descriptor () const noexcept -> k2::descriptor;
6165 auto reset (k2::descriptor descriptor) noexcept -> void;
6266 auto status () const noexcept -> k2::StreamStatus;
67+ auto set_blocking (bool blocking) noexcept -> void;
6368
6469 auto read (std::span<std::byte> buf) const noexcept -> kphp::coro::task<std::expected<size_t, int32_t>>;
6570 template <std::invocable<std::span<const std::byte>> F>
@@ -72,6 +77,28 @@ class stream {
7277
7378// ================================================================================================
7479
80+ inline auto stream::read_non_blocking (std::span<std::byte> buf) const noexcept -> std::expected<size_t, int32_t> {
81+ switch (status ().read_status ) {
82+ case k2::IOStatus::IOBlocked:
83+ return std::expected<size_t , int32_t >{0 };
84+ case k2::IOStatus::IOClosed:
85+ return std::unexpected{k2::errno_ebadfd};
86+ case k2::IOStatus::IOAvailable:
87+ return k2::read (m_descriptor, buf);
88+ }
89+ }
90+
91+ inline auto stream::write_non_blocking (std::span<const std::byte> buf) const noexcept -> std::expected<size_t, int32_t> {
92+ switch (status ().write_status ) {
93+ case k2::IOStatus::IOBlocked:
94+ return std::expected<size_t , int32_t >{0 };
95+ case k2::IOStatus::IOClosed:
96+ return std::unexpected{k2::errno_ebadfd};
97+ case k2::IOStatus::IOAvailable:
98+ return k2::write (m_descriptor, buf);
99+ }
100+ }
101+
75102inline auto stream::open (std::string_view target, k2::stream_kind stream_kind) noexcept -> std::expected<kphp::component::stream, int32_t> {
76103 int32_t errc{};
77104 k2::descriptor descriptor{k2::INVALID_PLATFORM_DESCRIPTOR };
@@ -125,7 +152,15 @@ inline auto stream::status() const noexcept -> k2::StreamStatus {
125152 return stream_status;
126153}
127154
155+ inline auto stream::set_blocking (bool blocking) noexcept -> void {
156+ m_non_blocking = !blocking;
157+ }
158+
128159inline auto stream::read (std::span<std::byte> buf) const noexcept -> kphp::coro::task<std::expected<size_t, int32_t>> {
160+ if (m_non_blocking) {
161+ co_return read_non_blocking (buf);
162+ }
163+
129164 for (size_t read{}; read < buf.size ();) {
130165 switch (co_await m_scheduler.poll (m_descriptor, kphp::coro::poll_op::read)) {
131166 case kphp::coro::poll_status::event:
@@ -158,6 +193,10 @@ auto stream::read_all(F f) const noexcept -> kphp::coro::task<std::expected<void
158193}
159194
160195inline auto stream::write (std::span<const std::byte> buf) const noexcept -> kphp::coro::task<std::expected<size_t, int32_t>> {
196+ if (m_non_blocking) {
197+ co_return write_non_blocking (buf);
198+ }
199+
161200 for (size_t written{}; written < buf.size ();) {
162201 switch (co_await m_scheduler.poll (m_descriptor, kphp::coro::poll_op::write)) {
163202 case kphp::coro::poll_status::event:
0 commit comments