1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#include <cassert>
#include <functional>
#include <istream>
#include <cm/memory>
#include <cm3p/uv.h>
#include "cmUVHandlePtr.h"
#include "cmUVStreambuf.h"
template <typename CharT, typename Traits = std::char_traits<CharT>>
class cmBasicUVIStream : public std::basic_istream<CharT>
{
public:
cmBasicUVIStream();
cmBasicUVIStream(uv_stream_t* stream);
bool is_open() const;
void open(uv_stream_t* stream);
void close();
private:
cmBasicUVStreambuf<CharT, Traits> Buffer;
};
template <typename CharT, typename Traits>
cmBasicUVIStream<CharT, Traits>::cmBasicUVIStream()
: std::basic_istream<CharT, Traits>(&this->Buffer)
{
}
template <typename CharT, typename Traits>
cmBasicUVIStream<CharT, Traits>::cmBasicUVIStream(uv_stream_t* stream)
: cmBasicUVIStream()
{
this->open(stream);
}
template <typename CharT, typename Traits>
bool cmBasicUVIStream<CharT, Traits>::is_open() const
{
return this->Buffer.is_open();
}
template <typename CharT, typename Traits>
void cmBasicUVIStream<CharT, Traits>::open(uv_stream_t* stream)
{
this->Buffer.open(stream);
}
template <typename CharT, typename Traits>
void cmBasicUVIStream<CharT, Traits>::close()
{
this->Buffer.close();
}
using cmUVIStream = cmBasicUVIStream<char>;
template <typename CharT, typename Traits = std::char_traits<CharT>>
class cmBasicUVPipeIStream : public cmBasicUVIStream<CharT, Traits>
{
public:
cmBasicUVPipeIStream();
cmBasicUVPipeIStream(uv_loop_t& loop, int fd);
using cmBasicUVIStream<CharT, Traits>::is_open;
void open(uv_loop_t& loop, int fd);
void close();
private:
cm::uv_pipe_ptr Pipe;
};
template <typename CharT, typename Traits>
cmBasicUVPipeIStream<CharT, Traits>::cmBasicUVPipeIStream() = default;
template <typename CharT, typename Traits>
cmBasicUVPipeIStream<CharT, Traits>::cmBasicUVPipeIStream(uv_loop_t& loop,
int fd)
{
this->open(loop, fd);
}
template <typename CharT, typename Traits>
void cmBasicUVPipeIStream<CharT, Traits>::open(uv_loop_t& loop, int fd)
{
this->Pipe.init(loop, 0);
uv_pipe_open(this->Pipe, fd);
this->cmBasicUVIStream<CharT, Traits>::open(this->Pipe);
}
template <typename CharT, typename Traits>
void cmBasicUVPipeIStream<CharT, Traits>::close()
{
this->cmBasicUVIStream<CharT, Traits>::close();
this->Pipe.reset();
}
using cmUVPipeIStream = cmBasicUVPipeIStream<char>;
class cmUVStreamReadHandle
{
private:
std::vector<char> Buffer;
std::function<void(std::vector<char>)> OnRead;
std::function<void()> OnFinish;
template <typename ReadCallback, typename FinishCallback>
friend std::unique_ptr<cmUVStreamReadHandle> cmUVStreamRead(
uv_stream_t* stream, ReadCallback onRead, FinishCallback onFinish);
};
template <typename ReadCallback, typename FinishCallback>
std::unique_ptr<cmUVStreamReadHandle> cmUVStreamRead(uv_stream_t* stream,
ReadCallback onRead,
FinishCallback onFinish)
{
auto handle = cm::make_unique<cmUVStreamReadHandle>();
handle->OnRead = std::move(onRead);
handle->OnFinish = std::move(onFinish);
stream->data = handle.get();
uv_read_start(
stream,
[](uv_handle_t* s, std::size_t suggestedSize, uv_buf_t* buffer) {
auto* data = static_cast<cmUVStreamReadHandle*>(s->data);
data->Buffer.resize(suggestedSize);
buffer->base = data->Buffer.data();
buffer->len = suggestedSize;
},
[](uv_stream_t* s, ssize_t nread, uv_buf_t const* buffer) {
auto* data = static_cast<cmUVStreamReadHandle*>(s->data);
if (nread > 0) {
(void)buffer;
assert(buffer->base == data->Buffer.data());
data->Buffer.resize(nread);
data->OnRead(std::move(data->Buffer));
} else if (nread < 0 /*|| nread == UV_EOF*/) {
data->OnFinish();
uv_read_stop(s);
}
});
return handle;
}
|