userver: userver/engine/io/prefixed_rw.hpp Source File
Loading...
Searching...
No Matches
prefixed_rw.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/io/prefixed_rw.hpp
4/// @brief @copybrief engine::io::PrefixedRw
5
6#include <memory>
7#include <optional>
8#include <string>
9
10#include <userver/engine/io/common.hpp>
11#include <userver/utils/fast_pimpl.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace engine::io {
16
17/// @ingroup userver_base_classes
18///
19/// @brief @ref RwBase adapter that returns a fixed byte prefix before reading
20/// from the underlying stream.
21///
22/// Useful when some already-received bytes must be replayed as if they were
23/// still unread on the socket (for example, handshake leftovers buffered by
24/// a third-party library).
25///
26/// Writes always go to the underlying stream. The readable awaitable reports
27/// ready while unread prefix bytes remain (so @ref engine::WaitAny wakes even
28/// if the underlying socket has no data yet); afterwards it follows the
29/// underlying stream.
30///
31/// @snippet engine/io/prefixed_rw_test.cpp Sample PrefixedRw
32class PrefixedRw final : public RwBase {
33public:
34 /// @param prefix Bytes returned by read APIs before touching @a underlying.
35 /// @param underlying Stream used after @a prefix is exhausted; must be non-null.
36 PrefixedRw(std::string prefix, std::unique_ptr<RwBase> underlying);
37
38 PrefixedRw(const PrefixedRw&) = delete;
39 PrefixedRw& operator=(const PrefixedRw&) = delete;
40
41 PrefixedRw(PrefixedRw&&) noexcept = delete;
42 PrefixedRw& operator=(PrefixedRw&&) noexcept = delete;
43
44 ~PrefixedRw() override;
45
46 /// Whether the underlying stream is valid.
47 bool IsValid() const override;
48
49 /// @returns true immediately while unread prefix bytes remain; otherwise
50 /// waits on the underlying stream.
51 [[nodiscard]] bool WaitReadable(Deadline deadline) override;
52
53 /// Waits on the underlying stream.
54 [[nodiscard]] bool WaitWriteable(Deadline deadline) override;
55
56 /// Reads from the prefix first, then from the underlying stream.
57 [[nodiscard]] std::optional<size_t> ReadNoblock(void* buf, size_t len) override;
58
59 /// Reads from the prefix first, then from the underlying stream.
60 [[nodiscard]] size_t ReadSome(void* buf, size_t len, Deadline deadline) override;
61
62 /// Reads from the prefix first, then from the underlying stream.
63 [[nodiscard]] size_t ReadAll(void* buf, size_t len, Deadline deadline) override;
64
65 /// Forwards to the underlying stream.
66 [[nodiscard]] size_t WriteAll(const void* buf, size_t len, Deadline deadline) override;
67
68 /// Forwards to the underlying stream.
69 [[nodiscard]] size_t WriteAll(std::span<const IoData> list, Deadline deadline) override;
70
71private:
72 class ReadAwaitable;
73
74 [[nodiscard]] bool HasUnreadPrefix() const noexcept { return prefix_pos_ < prefix_.size(); }
75
76 std::optional<size_t> ReadFromPrefix(void* buf, size_t len);
77
78 std::string prefix_;
79 std::size_t prefix_pos_{0};
80 std::unique_ptr<RwBase> underlying_;
81 // Size/alignment match PrefixedRw::ReadAwaitable (vptr + PrefixedRw&).
82 utils::FastPimpl<ReadAwaitable, 16, 8> read_awaitable_;
83};
84
85} // namespace engine::io
86
87USERVER_NAMESPACE_END