• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/flat_buffer.hpp>
15 #include <boost/asio/buffer.hpp>
16 #include <boost/asio/buffers_iterator.hpp>
17 #include <boost/asio/ip/tcp.hpp>
18 #include <boost/asio/spawn.hpp>
19 #include <boost/asio/use_future.hpp>
20 #include <boost/asio/write.hpp>
21 #include <algorithm>
22 #include <assert.h>
23 
24 namespace boost {
25 namespace beast {
26 
27 namespace {
28 
29 void
snippets()30 snippets()
31 {
32     #include "snippets.ipp"
33     {
34     //[code_core_1_refresher_1s
35         net::const_buffer cb("Hello, world!", 13);
36         assert(string_view(reinterpret_cast<char const*>(
37             cb.data()), cb.size()) == "Hello, world!");
38 
39         char storage[13];
40         net::mutable_buffer mb(storage, sizeof(storage));
41         std::memcpy(mb.data(), cb.data(), mb.size());
42         assert(string_view(reinterpret_cast<char const*>(
43             mb.data()), mb.size()) == "Hello, world!");
44     //]
45     }
46     {
47     //[code_core_1_refresher_2s
48         net::const_buffer b1;                   // a ConstBufferSequence by definition
49         net::mutable_buffer b2;                 // a MutableBufferSequence by definition
50         std::array<net::const_buffer, 3> b3;    // A ConstBufferSequence by named requirements
51     //]
52     }
53     {
54     //[code_core_1_refresher_3s
55         // initiate an asynchronous write operation
56         net::async_write(sock, net::const_buffer("Hello, world!", 13),
57             [](error_code ec, std::size_t bytes_transferred)
58             {
59                 // this lambda is invoked when the write operation completes
60                 if(! ec)
61                     assert(bytes_transferred == 13);
62                 else
63                     std::cerr << "Error: " << ec.message() << "\n";
64             });
65         // meanwhile, the operation is outstanding and execution continues from here
66     //]
67     }
68     {
69     //[code_core_1_refresher_4s
70         std::future<std::size_t> f = net::async_write(sock,
71             net::const_buffer("Hello, world!", 13), net::use_future);
72     //]
73     }
74     {
75     //[code_core_1_refresher_5s
76         asio::spawn(
77             [&sock](net::yield_context yield)
78             {
79                 std::size_t bytes_transferred = net::async_write(sock,
80                     net::const_buffer("Hello, world!", 13), yield);
81                 (void)bytes_transferred;
82             });
83     //]
84     }
85 }
86 
87 //------------------------------------------------------------------------------
88 
89 //[code_core_1_refresher_1
90 template <class ConstBufferSequence>
string_from_buffers(ConstBufferSequence const & buffers)91 std::string string_from_buffers (ConstBufferSequence const& buffers)
92 {
93     // check that the type meets the requirements using the provided type traits
94     static_assert(
95         net::is_const_buffer_sequence<ConstBufferSequence>::value,
96         "ConstBufferSequence type requirements not met");
97 
98     // optimization: reserve all the space for the string first
99     std::string result;
100     result.reserve(beast::buffer_bytes(buffers));        // beast version of net::buffer_size
101 
102     // iterate over each buffer in the sequence and append it to the string
103     for(auto it = net::buffer_sequence_begin(buffers);  // returns an iterator to beginning of the sequence
104         it != net::buffer_sequence_end(buffers);)       // returns a past-the-end iterator to the sequence
105     {
106         // A buffer sequence iterator's value_type is always convertible to net::const_buffer
107         net::const_buffer buffer = *it++;
108 
109         // A cast is always required to out-out of type-safety
110         result.append(static_cast<char const*>(buffer.data()), buffer.size());
111     }
112     return result;
113 }
114 //]
115 
116 //------------------------------------------------------------------------------
117 
118 //[code_core_1_refresher_2
119 // Read a line ending in '\n' from a socket, returning
120 // the number of characters up to but not including the newline
121 template <class DynamicBuffer>
read_line(net::ip::tcp::socket & sock,DynamicBuffer & buffer)122 std::size_t read_line(net::ip::tcp::socket& sock, DynamicBuffer& buffer)
123 {
124     // this alias keeps things readable
125     using range = net::buffers_iterator<
126         typename DynamicBuffer::const_buffers_type>;
127 
128     for(;;)
129     {
130         // get iterators representing the range of characters in the buffer
131         auto begin = range::begin(buffer.data());
132         auto end = range::end(buffer.data());
133 
134         // search for "\n" and return if found
135         auto pos = std::find(begin, end, '\n');
136         if(pos != range::end(buffer.data()))
137             return std::distance(begin, end);
138 
139         // Determine the number of bytes to read,
140         // using available capacity in the buffer first.
141         std::size_t bytes_to_read = std::min<std::size_t>(
142               std::max<std::size_t>(512,                // under 512 is too little,
143                   buffer.capacity() - buffer.size()),
144               std::min<std::size_t>(65536,              // and over 65536 is too much.
145                   buffer.max_size() - buffer.size()));
146 
147         // Read up to bytes_to_read bytes into the dynamic buffer
148         buffer.commit(sock.read_some(buffer.prepare(bytes_to_read)));
149     }
150 }
151 //]
152 
153 //------------------------------------------------------------------------------
154 
155 //[code_core_1_refresher_3
156 // Meets the requirements of SyncReadStream
157 struct sync_read_stream
158 {
159     // Returns the number of bytes read upon success, otherwise throws an exception
160     template <class MutableBufferSequence>
161     std::size_t read_some(MutableBufferSequence const& buffers);
162 
163     // Returns the number of bytes read successfully, sets the error code if a failure occurs
164     template <class MutableBufferSequence>
165     std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec);
166 };
167 
168 // Meets the requirements of SyncWriteStream
169 struct sync_write_stream
170 {
171     // Returns the number of bytes written upon success, otherwise throws an exception
172     template <class ConstBufferSequence>
173     std::size_t write_some(ConstBufferSequence const& buffers);
174 
175     // Returns the number of bytes written successfully, sets the error code if a failure occurs
176     template <class ConstBufferSequence>
177     std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec);
178 };
179 //]
180 
181 template<class MutableBufferSequence>
read_some(MutableBufferSequence const &)182 std::size_t sync_read_stream::read_some(MutableBufferSequence const&)
183 {
184     return 0;
185 }
186 template<class MutableBufferSequence>
read_some(MutableBufferSequence const &,error_code &)187 std::size_t sync_read_stream::read_some(MutableBufferSequence const&, error_code&)
188 {
189     return 0;
190 }
191 template<class ConstBufferSequence>
write_some(ConstBufferSequence const &)192 std::size_t sync_write_stream::write_some(ConstBufferSequence const&)
193 {
194     return 0;
195 }
196 template<class ConstBufferSequence>
write_some(ConstBufferSequence const &,error_code &)197 std::size_t sync_write_stream::write_some(ConstBufferSequence const&, error_code&)
198 {
199     return 0;
200 }
201 BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
202 BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
203 
204 //------------------------------------------------------------------------------
205 
206 //[code_core_1_refresher_4
207 template <class SyncWriteStream>
hello(SyncWriteStream & stream)208 void hello (SyncWriteStream& stream)
209 {
210     net::const_buffer cb("Hello, world!", 13);
211     do
212     {
213         auto bytes_transferred = stream.write_some(cb); // may throw
214         cb += bytes_transferred; // adjust the pointer and size
215     }
216     while (cb.size() > 0);
217 }
218 //]
219 
220 //------------------------------------------------------------------------------
221 
222 //[code_core_1_refresher_5
223 template <class SyncWriteStream>
hello(SyncWriteStream & stream,error_code & ec)224 void hello (SyncWriteStream& stream, error_code& ec)
225 {
226     net::const_buffer cb("Hello, world!", 13);
227     do
228     {
229         auto bytes_transferred = stream.write_some(cb, ec);
230         cb += bytes_transferred; // adjust the pointer and size
231     }
232     while (cb.size() > 0 && ! ec);
233 }
234 //]
235 
236 //------------------------------------------------------------------------------
237 
238 } // (anon)
239 } // beast
240 } // boost
241 
242 //[code_core_1_refresher_6
243 // The following is a completion handler expressed
244 // as a function object, with a nested associated
245 // allocator and a nested associated executor.
246 struct handler
247 {
248     using allocator_type = std::allocator<char>;
249     allocator_type get_allocator() const noexcept;
250 
251     using executor_type = boost::asio::io_context::executor_type;
252     executor_type get_executor() const noexcept;
253 
254     void operator()(boost::beast::error_code, std::size_t);
255 };
256 //]
get_allocator() const257 inline auto handler::get_allocator() const noexcept ->
258     allocator_type
259 {
260     return {};
261 }
get_executor() const262 inline auto handler::get_executor() const noexcept ->
263     executor_type
264 {
265     static boost::asio::io_context ioc;
266     return ioc.get_executor();
267 }
operator ()(boost::beast::error_code,std::size_t)268 inline void handler::operator()(
269     boost::beast::error_code, std::size_t)
270 {
271 }
272 
273 //[code_core_1_refresher_7
274 namespace boost {
275 namespace asio {
276 
277 template<class Allocator>
278 struct associated_allocator<handler, Allocator>
279 {
280     using type = std::allocator<void>;
281 
282     static
283     type
284     get(handler const& h,
285         Allocator const& alloc = Allocator{}) noexcept;
286 };
287 
288 template<class Executor>
289 struct associated_executor<handler, Executor>
290 {
291     using type = any_io_executor;
292 
293     static
294     type
295     get(handler const& h,
296         Executor const& ex = Executor{}) noexcept;
297 };
298 
299 } // boost
300 } // asio
301 //]
302 
303 template<class Allocator>
304 auto
305 boost::asio::associated_allocator<handler, Allocator>::
get(handler const &,Allocator const &)306 get(handler const&, Allocator const&) noexcept -> type
307 {
308     return {};
309 }
310 template<class Executor>
311 auto
312 boost::asio::associated_executor<handler, Executor>::
get(handler const &,Executor const &)313 get(handler const&, Executor const&) noexcept -> type
314 {
315     return {};
316 }
317 
318 //------------------------------------------------------------------------------
319 
320 namespace boost {
321 namespace beast {
322 
323 namespace {
324 
325 //------------------------------------------------------------------------------
326 
327 //[code_core_1_refresher_8
328 template <class AsyncWriteStream, class WriteHandler>
async_hello(AsyncWriteStream & stream,WriteHandler && handler)329 void async_hello (AsyncWriteStream& stream, WriteHandler&& handler)
330 {
331     net::async_write (stream,
332         net::buffer("Hello, world!", 13),
333         std::forward<WriteHandler>(handler));
334 }
335 //]
336 
337 //------------------------------------------------------------------------------
338 
339 //[code_core_1_refresher_9
340 template<
341     class AsyncWriteStream,
342     class ConstBufferSequence,
343     class CompletionToken>
344 auto
345 async_write(
346     AsyncWriteStream* stream,                       // references are passed as pointers
347     ConstBufferSequence const& buffers,
348     CompletionToken&& token)                        // a handler, or a special object.
349     ->
350     typename net::async_result<                     // return-type customization point.
351         typename std::decay<CompletionToken>::type, // type used to specialize async_result.
352         void(error_code, std::size_t)               // underlying completion handler signature.
353             >::return_type;
354 //]
355 struct run_async_write
356 {
357     template<class... Args>
358     void
operator ()boost::beast::__anone1eee1320411::run_async_write359     operator()(Args&&...)
360     {
361     }
362 };
363 template<
364     class AsyncWriteStream,
365     class ConstBufferSequence,
366     class CompletionToken>
367 auto
async_write(AsyncWriteStream & stream,ConstBufferSequence const & buffers,CompletionToken && token)368 async_write(
369     AsyncWriteStream& stream,
370     ConstBufferSequence const& buffers,
371     CompletionToken&& token) ->
372         typename net::async_result<
373             typename std::decay<CompletionToken>::type,
374             void(error_code, std::size_t)
375                 >::return_type
376 {
377 //[code_core_1_refresher_10
378 
379     return net::async_initiate<
380         CompletionToken,
381         void(error_code, std::size_t)>(
382             run_async_write{},              // The "initiation" object.
383             token,                          // Token must come before other arguments.
384             &stream,                        // Additional captured arguments are
385             buffers);                       //   forwarded to the initiation object.
386 
387 //]
388 }
389 
390 //------------------------------------------------------------------------------
391 
392 } // (anon)
393 
394 struct core_1_refresher_test
395     : public beast::unit_test::suite
396 {
397     void
runboost::beast::core_1_refresher_test398     run() override
399     {
400         BEAST_EXPECT(&snippets);
401 
402         BEAST_EXPECT((static_cast<
403             std::string(*)(net::const_buffer const&)>(
404                 &string_from_buffers<net::const_buffer>)));
405 
406         BEAST_EXPECT(static_cast<
407             std::size_t(*)(net::ip::tcp::socket&, flat_buffer&)>(
408                 &read_line<flat_buffer>));
409 
410         BEAST_EXPECT(static_cast<
411             std::size_t(sync_read_stream::*)(
412                 net::mutable_buffer const&)>(
413                     &sync_read_stream::read_some));
414         BEAST_EXPECT(static_cast<
415             std::size_t(sync_read_stream::*)(
416                 net::mutable_buffer const&, error_code&)>(
417                     &sync_read_stream::read_some));
418         BEAST_EXPECT(static_cast<
419             std::size_t(sync_write_stream::*)(
420                 net::const_buffer const&)>(
421                     &sync_write_stream::write_some));
422         BEAST_EXPECT(static_cast<
423             std::size_t(sync_write_stream::*)(
424                 net::const_buffer const&, error_code&)>(
425                     &sync_write_stream::write_some));
426 
427         BEAST_EXPECT(static_cast<
428             void(*)(test::stream&)>(
429             &hello<test::stream>));
430 
431         BEAST_EXPECT(static_cast<
432             void(*)(test::stream&, error_code&)>(
433             &hello<test::stream>));
434 
435         handler h;
436         h.get_allocator();
437         h.get_executor();
438 
439         BEAST_EXPECT((&async_hello<test::stream, handler>));
440     }
441 };
442 
443 BEAST_DEFINE_TESTSUITE(beast,doc,core_1_refresher);
444 
445 } // beast
446 } // boost
447