Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / beast / test / doc / core_4_layers.cpp
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #include "snippets.hpp"
11
12 #include <boost/beast/_experimental/unit_test/suite.hpp>
13 #include <boost/beast/_experimental/test/stream.hpp>
14 #include <boost/beast/core/async_base.hpp>
15 #include <boost/beast/core/error.hpp>
16 #include <boost/beast/core/stream_traits.hpp>
17 #include <boost/beast/websocket.hpp>
18 #include <cstdlib>
19 #include <utility>
20
21 namespace boost {
22 namespace beast {
23
24 void
25 core_4_layers_snippets()
26 {
27     #include "snippets.ipp"
28     {
29     //[code_core_4_layers_1
30
31         net::ssl::stream<net::ip::tcp::socket> ss(ioc, ctx);
32
33     //]
34     }
35     {
36     //[code_core_4_layers_2
37
38         websocket::stream<net::ip::tcp::socket> ws(ioc);
39
40     //]
41     }
42     //[code_core_4_layers_3
43
44         websocket::stream<net::ssl::stream<net::ip::tcp::socket>> ws(ioc, ctx);
45
46     //]
47 }
48
49 //[code_core_4_layers_4
50
51 // Set non-blocking mode on a stack of stream
52 // layers with a regular socket at the lowest layer.
53 template <class Stream>
54 void set_non_blocking (Stream& stream)
55 {
56     error_code ec;
57     // A compile error here means your lowest layer is not the right type!
58     get_lowest_layer(stream).non_blocking(true, ec);
59     if(ec)
60         throw system_error{ec};
61 }
62
63 //]
64
65 //[code_core_4_layers_5
66
67 // A layered stream which counts the bytes read and bytes written on the next layer
68 template <class NextLayer>
69 class counted_stream
70 {
71     NextLayer next_layer_;              // Reads and writes are passed through to this
72     std::size_t bytes_read_ = 0;        // Holds the total bytes read
73     std::size_t bytes_written_ = 0;     // Holds the total bytes written
74
75     // This is the "initiation" object passed to async_initiate to start the operation
76     struct run_read_op
77     {
78         template<
79             class ReadHandler,
80             class MutableBufferSequence>
81         void
82         operator()(
83             ReadHandler&& handler,
84             counted_stream* stream,
85             MutableBufferSequence const& buffers)
86         {
87             using handler_type = typename std::decay<ReadHandler>::type;
88
89             // async_base handles all of the composed operation boilerplate for us
90             using base = async_base<
91                 handler_type, beast::executor_type<NextLayer>>;
92
93             // Our composed operation is implemented as a completion handler object
94             struct op : base
95             {
96                 counted_stream& stream_;
97
98                 op( counted_stream& stream,
99                     handler_type&& handler,
100                     MutableBufferSequence const& buffers)
101                     : base(std::move(handler), stream.get_executor())
102                     , stream_(stream)
103                 {
104                     // Start the asynchronous operation
105                     stream_.next_layer().async_read_some(buffers, std::move(*this));
106                 }
107
108                 void operator()(error_code ec, std::size_t bytes_transferred)
109                 {
110                     // Count the bytes transferred towards the total
111                     stream_.bytes_read_ += bytes_transferred;
112
113                     this->complete_now(ec, bytes_transferred);
114                 }
115             };
116
117             op(*stream, std::forward<ReadHandler>(handler), buffers);
118         }
119     };
120
121     // This is the "initiation" object passed to async_initiate to start the operation
122     struct run_write_op
123     {
124         template<
125             class WriteHandler,
126             class ConstBufferSequence>
127         void
128         operator()(
129             WriteHandler&& handler,
130             counted_stream* stream,
131             ConstBufferSequence const& buffers)
132         {
133             using handler_type = typename std::decay<WriteHandler>::type;
134
135             // async_base handles all of the composed operation boilerplate for us
136             using base = async_base<
137                 handler_type, beast::executor_type<NextLayer>>;
138
139             // Our composed operation is implemented as a completion handler object
140             struct op : base
141             {
142                 counted_stream& stream_;
143
144                 op( counted_stream& stream,
145                     handler_type&& handler,
146                     ConstBufferSequence const& buffers)
147                     : base(std::move(handler), stream.get_executor())
148                     , stream_(stream)
149                 {
150                     // Start the asynchronous operation
151                     stream_.next_layer().async_write_some(buffers, std::move(*this));
152                 }
153
154                 void operator()(error_code ec, std::size_t bytes_transferred)
155                 {
156                     // Count the bytes transferred towards the total
157                     stream_.bytes_written_ += bytes_transferred;
158
159                     this->complete_now(ec, bytes_transferred);
160                 }
161             };
162
163             op(*stream, std::forward<WriteHandler>(handler), buffers);
164         }
165     };
166
167 public:
168     /// The type of executor used by this stream
169     using executor_type = beast::executor_type<NextLayer>;
170
171     /// Constructor
172     template <class... Args>
173     explicit
174     counted_stream(Args&&... args)
175         : next_layer_(std::forward<Args>(args)...)
176     {
177     }
178
179     /// Returns an instance of the executor used to submit completion handlers
180     executor_type get_executor() noexcept
181     {
182         return next_layer_.get_executor();
183     }
184
185     /// Returns a reference to the next layer
186     NextLayer& next_layer() noexcept
187     {
188         return next_layer_;
189     }
190
191     /// Returns a reference to the next layer
192     NextLayer const& next_layer() const noexcept
193     {
194         return next_layer_;
195     }
196
197     /// Returns the total number of bytes read since the stream was constructed
198     std::size_t bytes_read() const noexcept
199     {
200         return bytes_read_;
201     }
202
203     /// Returns the total number of bytes written since the stream was constructed
204     std::size_t bytes_written() const noexcept
205     {
206         return bytes_written_;
207     }
208
209     /// Read some data from the stream
210     template <class MutableBufferSequence>
211     std::size_t read_some(MutableBufferSequence const& buffers)
212     {
213         auto const bytes_transferred = next_layer_.read_some(buffers);
214         bytes_read_ += bytes_transferred;
215         return bytes_transferred;
216     }
217
218     /// Read some data from the stream
219     template <class MutableBufferSequence>
220     std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec)
221     {
222         auto const bytes_transferred = next_layer_.read_some(buffers, ec);
223         bytes_read_ += bytes_transferred;
224         return bytes_transferred;
225     }
226
227     /// Write some data to the stream
228     template <class ConstBufferSequence>
229     std::size_t write_some(ConstBufferSequence const& buffers)
230     {
231         auto const bytes_transferred = next_layer_.write_some(buffers);
232         bytes_written_ += bytes_transferred;
233         return bytes_transferred;
234     }
235
236     /// Write some data to the stream
237     template <class ConstBufferSequence>
238     std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec)
239     {
240         auto const bytes_transferred = next_layer_.write_some(buffers, ec);
241         bytes_written_ += bytes_transferred;
242         return bytes_transferred;
243     }
244
245     /// Read some data from the stream asynchronously
246     template<
247         class MutableBufferSequence,
248         class ReadHandler =
249             net::default_completion_token_t<executor_type>>
250     BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
251     async_read_some(
252         MutableBufferSequence const& buffers,
253         ReadHandler&& handler =
254             net::default_completion_token_t<executor_type>{})
255     {
256         return net::async_initiate<
257             ReadHandler,
258             void(error_code, std::size_t)>(
259                 run_read_op{},
260                 handler,
261                 this,
262                 buffers);
263     }
264
265     /// Write some data to the stream asynchronously
266     template<
267         class ConstBufferSequence,
268         class WriteHandler =
269             net::default_completion_token_t<executor_type>>
270     BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
271     async_write_some(
272         ConstBufferSequence const& buffers,
273         WriteHandler&& handler =
274             net::default_completion_token_t<
275                 executor_type>{})
276     {
277         return net::async_initiate<
278             WriteHandler,
279             void(error_code, std::size_t)>(
280                 run_write_op{},
281                 handler,
282                 this,
283                 buffers);
284     }
285 };
286 //]
287
288 template class counted_stream<test::stream>;
289
290 BOOST_STATIC_ASSERT(is_sync_read_stream<counted_stream<test::stream>>::value);
291 BOOST_STATIC_ASSERT(is_sync_write_stream<counted_stream<test::stream>>::value);
292 BOOST_STATIC_ASSERT(is_async_read_stream<counted_stream<test::stream>>::value);
293 BOOST_STATIC_ASSERT(is_async_write_stream<counted_stream<test::stream>>::value);
294
295 struct core_4_layers_test
296     : public beast::unit_test::suite
297 {
298     struct handler
299     {
300         void operator()(error_code, std::size_t)
301         {
302         }
303     };
304
305     void
306     run() override
307     {
308         BEAST_EXPECT(&core_4_layers_snippets);
309         BEAST_EXPECT(&set_non_blocking<net::ip::tcp::socket>);
310     }
311 };
312
313 BEAST_DEFINE_TESTSUITE(beast,doc,core_4_layers);
314
315 } // beast
316 } // boost