GCC Code Coverage Report


Directory: ./
File: libs/http_proto/include/boost/http_proto/serializer.hpp
Date: 2025-12-22 14:47:58
Exec Total Coverage
Lines: 9 9 100.0%
Functions: 4 4 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2025 Mohammad Nejati
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/http_proto
9 //
10
11 #ifndef BOOST_HTTP_PROTO_SERIALIZER_HPP
12 #define BOOST_HTTP_PROTO_SERIALIZER_HPP
13
14 #include <boost/http_proto/detail/config.hpp>
15 #include <boost/http_proto/detail/workspace.hpp>
16 #include <boost/http_proto/source.hpp>
17
18 #include <boost/buffers/buffer_pair.hpp>
19 #include <boost/core/span.hpp>
20 #include <boost/capy/polystore_fwd.hpp>
21 #include <boost/system/result.hpp>
22
23 #include <type_traits>
24 #include <utility>
25
26 namespace boost {
27 namespace http_proto {
28
29 // Forward declaration
30 class message_base;
31
32 /** A serializer for HTTP/1 messages
33
34 This is used to serialize one or more complete
35 HTTP/1 messages. Each message consists of a
36 required header followed by an optional body.
37
38 Objects of this type operate using an "input area" and an
39 "output area". Callers provide data to the input area
40 using one of the @ref start or @ref start_stream member
41 functions. After input is provided, serialized data
42 becomes available in the serializer's output area in the
43 form of a constant buffer sequence.
44
45 Callers alternate between filling the input area and
46 consuming the output area until all the input has been
47 provided and all the output data has been consumed, or
48 an error occurs.
49
50 After calling @ref start, the caller must ensure that the
51 contents of the associated message are not changed or
52 destroyed until @ref is_done returns true, @ref reset is
53 called, or the serializer is destroyed, otherwise the
54 behavior is undefined.
55 */
56 class serializer
57 {
58 public:
59 class stream;
60 struct config;
61
62 /** The type used to represent a sequence of
63 constant buffers that refers to the output
64 area.
65 */
66 using const_buffers_type =
67 boost::span<buffers::const_buffer const>;
68
69 /** Destructor
70 */
71 BOOST_HTTP_PROTO_DECL
72 ~serializer();
73
74 /** Constructor
75 Default-constructed serializers do not reference any implementation;
76 the only valid operations are destruction and assignment.
77 */
78 3 serializer() = default;
79
80 /** Constructor.
81
82 The states of `other` are transferred
83 to the newly constructed object,
84 which includes the allocated buffer.
85 After construction, the only valid
86 operations on the moved-from object
87 are destruction and assignment.
88
89 Buffer sequences previously obtained
90 using @ref prepare or @ref stream::prepare
91 remain valid.
92
93 @par Postconditions
94 @code
95 other.is_done() == true
96 @endcode
97
98 @par Complexity
99 Constant.
100
101 @param other The serializer to move from.
102 */
103 BOOST_HTTP_PROTO_DECL
104 serializer(
105 serializer&& other) noexcept;
106
107 /** Assignment.
108 The states of `other` are transferred
109 to this object, which includes the
110 allocated buffer. After assignment,
111 the only valid operations on the
112 moved-from object are destruction and
113 assignment.
114 Buffer sequences previously obtained
115 using @ref prepare or @ref stream::prepare
116 remain valid.
117 @par Complexity
118 Constant.
119 @param other The serializer to move from.
120 @return A reference to this object.
121 */
122 BOOST_HTTP_PROTO_DECL
123 serializer&
124 operator=(serializer&& other) noexcept;
125
126 /** Constructor.
127
128 Constructs a serializer that uses the @ref
129 config parameters installed on the
130 provided `ctx`.
131
132 The serializer will attempt to allocate
133 the required space on startup, with the
134 amount depending on the @ref config
135 parameters, and will not perform any
136 further allocations, except for Brotli
137 encoder instances, if enabled.
138
139 Depending on which compression algorithms
140 are enabled in the @ref config, the
141 serializer will attempt to access the
142 corresponding encoder services on the same
143 `ctx`.
144
145 @par Example
146 @code
147 serializer sr(ctx);
148 @endcode
149
150 @par Postconditions
151 @code
152 this->is_done() == true
153 @endcode
154
155 @par Complexity
156 Constant.
157
158 @par Exception Safety
159 Calls to allocate may throw.
160
161 @param ctx Context from which the
162 serializer will access registered
163 services. The caller is responsible for
164 ensuring that the provided ctx remains
165 valid for the lifetime of the serializer.
166
167 @see
168 @ref install_serializer_service,
169 @ref config.
170 */
171 BOOST_HTTP_PROTO_DECL
172 explicit
173 serializer(
174 capy::polystore& ctx);
175
176 /** Reset the serializer for a new message.
177
178 Aborts any ongoing serialization and
179 prepares the serializer to start
180 serialization of a new message.
181 */
182 BOOST_HTTP_PROTO_DECL
183 void
184 reset() noexcept;
185
186 /** Start serializing a message with an empty body
187
188 This function prepares the serializer to create a message which
189 has an empty body.
190 Ownership of the specified message is not transferred; the caller is
191 responsible for ensuring the lifetime of the object extends until the
192 serializer is done.
193
194 @par Preconditions
195 @code
196 this->is_done() == true
197 @endcode
198
199 @par Postconditions
200 @code
201 this->is_done() == false
202 @endcode
203
204 @par Exception Safety
205 Strong guarantee.
206 Exceptions thrown if there is insufficient internal buffer space
207 to start the operation.
208
209 @throw std::logic_error `this->is_done() == true`.
210
211 @throw std::length_error if there is insufficient internal buffer
212 space to start the operation.
213
214 @param m The request or response headers to serialize.
215
216 @see
217 @ref message_base.
218 */
219 void
220 BOOST_HTTP_PROTO_DECL
221 start(message_base const& m);
222
223 /** Start serializing a message with a buffer sequence body
224
225 Initializes the serializer with the HTTP start-line and headers from `m`,
226 and the provided `buffers` for reading the message body from.
227
228 Changing the contents of the message after calling this function and
229 before @ref is_done returns `true` results in undefined behavior.
230
231 At least one copy of the specified buffer sequence is maintained until
232 the serializer is done, gets reset, or ios destroyed, after which all
233 of its copies are destroyed. Ownership of the underlying memory is not
234 transferred; the caller must ensure the memory remains valid until the
235 serializer’s copies are destroyed.
236
237 @par Preconditions
238 @code
239 this->is_done() == true
240 @endcode
241
242 @par Postconditions
243 @code
244 this->is_done() == false
245 @endcode
246
247 @par Constraints
248 @code
249 buffers::is_const_buffer_sequence_v<ConstBufferSequence> == true
250 @endcode
251
252 @par Exception Safety
253 Strong guarantee.
254 Exceptions thrown if there is insufficient internal buffer space
255 to start the operation.
256
257 @throw std::logic_error `this->is_done() == true`.
258
259 @throw std::length_error If there is insufficient internal buffer
260 space to start the operation.
261
262 @param m The message to read the HTTP start-line and headers from.
263
264 @param buffers A buffer sequence containing the message body.
265
266 containing the message body data. While
267 the buffers object is copied, ownership of
268 the underlying memory remains with the
269 caller, who must ensure it stays valid
270 until @ref is_done returns `true`.
271
272 @see
273 @ref message_base.
274 */
275 template<
276 class ConstBufferSequence,
277 class = typename std::enable_if<
278 buffers::is_const_buffer_sequence<
279 ConstBufferSequence>::value>::type
280 >
281 void
282 start(
283 message_base const& m,
284 ConstBufferSequence&& buffers);
285
286 /** Start serializing a message with a @em Source body
287
288 Initializes the serializer with the HTTP start-line and headers from
289 `m`, and constructs a `Source` object to provide the message body.
290
291 Changing the contents of the message
292 after calling this function and before
293 @ref is_done returns `true` results in
294 undefined behavior.
295
296 The serializer destroys Source object when:
297 @li `this->is_done() == true`
298 @li An unrecoverable serialization error occurs
299 @li The serializer is destroyed
300
301 @par Example
302 @code
303 file f("example.zip", file_mode::scan);
304 response.set_payload_size(f.size());
305 serializer.start<file_source>(response, std::move(f));
306 @endcode
307
308 @par Preconditions
309 @code
310 this->is_done() == true
311 @endcode
312
313 @par Postconditions
314 @code
315 this->is_done() == false
316 @endcode
317
318 @par Constraints
319 @code
320 is_source<Source>::value == true
321 @endcode
322
323 @par Exception Safety
324 Strong guarantee.
325 Exceptions thrown if there is insufficient
326 internal buffer space to start the
327 operation.
328
329 @throw std::length_error if there is
330 insufficient internal buffer space to
331 start the operation.
332
333 @param m The message to read the HTTP
334 start-line and headers from.
335
336 @param args Arguments to be passed to the
337 `Source` constructor.
338
339 @return A reference to the constructed Source object.
340
341 @see
342 @ref source,
343 @ref file_source,
344 @ref message_base.
345 */
346 template<
347 class Source,
348 class... Args,
349 class = typename std::enable_if<
350 is_source<Source>::value>::type>
351 Source&
352 start(
353 message_base const& m,
354 Args&&... args);
355
356 /** Prepare the serializer for a new message using a stream interface.
357
358 Initializes the serializer with the HTTP
359 start-line and headers from `m`, and returns
360 a @ref stream object for writing the body
361 data into the serializer's internal buffer.
362
363 Once the serializer is destroyed, @ref reset
364 is called, or @ref is_done returns true, the
365 only valid operation on the stream is destruction.
366
367 The stream allows inverted control flow: the
368 caller supplies body data to the serializer’s
369 internal buffer while reading from an external
370 source.
371
372 Changing the contents of the message
373 after calling this function and before
374 @ref is_done returns `true` results in
375 undefined behavior.
376
377 @par Example
378 @code
379 serializer::stream st = serializer.start_stream(response);
380 do
381 {
382 if(st.is_open())
383 {
384 std::size_t n = source.read_some(st.prepare());
385
386 if(ec == error::eof)
387 st.close();
388 else
389 st.commit(n);
390 }
391
392 write_some(client, serializer);
393
394 } while(!serializer.is_done());
395 @endcode
396
397 @par Preconditions
398 @code
399 this->is_done() == true
400 @endcode
401
402 @par Postconditions
403 @code
404 this->is_done() == false
405 @endcode
406
407 @par Exception Safety
408 Strong guarantee.
409 Exceptions thrown if there is insufficient
410 internal buffer space to start the
411 operation.
412
413 @throw std::length_error if there is
414 insufficient internal buffer space to
415 start the operation.
416
417 @param m The message to read the HTTP
418 start-line and headers from.
419
420 @return A @ref stream object for writing the body
421 data into the serializer's internal buffer.
422
423 @see
424 @ref stream,
425 @ref message_base.
426 */
427 BOOST_HTTP_PROTO_DECL
428 stream
429 start_stream(
430 message_base const& m);
431
432 /** Return the output area.
433
434 This function serializes some or all of
435 the message and returns the corresponding
436 output buffers. Afterward, a call to @ref
437 consume is required to report the number
438 of bytes used, if any.
439
440 If the message includes an
441 `Expect: 100-continue` header and the
442 header section of the message has been
443 consumed, the returned result will contain
444 @ref error::expect_100_continue to
445 indicate that the header part of the
446 message is complete. The next call to @ref
447 prepare will produce output.
448
449 When the serializer is used through the
450 @ref stream interface, the result may
451 contain @ref error::need_data to indicate
452 that additional input is required to
453 produce output.
454
455 If a @ref source object is in use and a
456 call to @ref source::read returns an
457 error, the serializer enters a faulted
458 state and propagates the error to the
459 caller. This faulted state can only be
460 cleared by calling @ref reset. This
461 ensures the caller is explicitly aware
462 that the previous message was truncated
463 and that the stream must be terminated.
464
465 @par Preconditions
466 @code
467 this->is_done() == false
468 @endcode
469 No unrecoverable error reported from previous calls.
470
471 @par Exception Safety
472 Strong guarantee.
473 Calls to @ref source::read may throw if in use.
474
475 @throw std::logic_error
476 `this->is_done() == true`.
477
478 @return A result containing @ref
479 const_buffers_type that represents the
480 output area or an error if any occurred.
481
482 @see
483 @ref consume,
484 @ref is_done,
485 @ref const_buffers_type.
486 */
487 BOOST_HTTP_PROTO_DECL
488 auto
489 prepare() ->
490 system::result<
491 const_buffers_type>;
492
493 /** Consume bytes from the output area.
494
495 This function should be called after one
496 or more bytes contained in the buffers
497 provided in the prior call to @ref prepare
498 have been used.
499
500 After a call to @ref consume, callers
501 should check the return value of @ref
502 is_done to determine if the entire message
503 has been serialized.
504
505 @par Preconditions
506 @code
507 this->is_done() == false
508 @endcode
509
510 @par Exception Safety
511 Strong guarantee.
512
513 @throw std::logic_error
514 `this->is_done() == true`.
515
516 @param n The number of bytes to consume.
517 If `n` is greater than the size of the
518 buffer returned from @ref prepared the
519 entire output sequence is consumed and no
520 error is issued.
521
522 @see
523 @ref prepare,
524 @ref is_done,
525 @ref const_buffers_type.
526 */
527 BOOST_HTTP_PROTO_DECL
528 void
529 consume(std::size_t n);
530
531 /** Return true if serialization is complete.
532 */
533 BOOST_HTTP_PROTO_DECL
534 bool
535 is_done() const noexcept;
536
537 /** Return true if headers have been set.
538
539 Returns `true` if @ref set_headers has been
540 called and no @ref start or @ref start_stream
541 function has been called since. This indicates
542 that the serializer is ready to begin
543 serialization with a body style.
544
545 @see
546 @ref set_headers,
547 @ref is_done.
548 */
549 BOOST_HTTP_PROTO_DECL
550 bool
551 is_headers_set() const noexcept;
552
553 /** Set the message headers for serialization.
554
555 This function prepares the serializer with the
556 HTTP start-line and headers from `m`. After
557 calling this function, one of the @ref start
558 or @ref start_stream overloads that do not
559 take a message parameter must be called to
560 begin serialization.
561
562 Changing the contents of the message after
563 calling this function and before @ref is_done
564 returns `true` results in undefined behavior.
565
566 @par Preconditions
567 @code
568 this->is_done() == true
569 @endcode
570
571 @par Exception Safety
572 Strong guarantee.
573
574 @throw std::logic_error `this->is_done() == false`.
575
576 @param m The request or response headers to serialize.
577
578 @see
579 @ref message_base.
580 */
581 BOOST_HTTP_PROTO_DECL
582 void
583 set_headers(message_base const& m);
584
585 /** Start serializing a message with an empty body.
586
587 This overload requires @ref set_headers to have
588 been called first.
589
590 @par Preconditions
591 @ref set_headers has been called and no @ref start
592 or @ref start_stream function has been called since.
593
594 @par Postconditions
595 @code
596 this->is_done() == false
597 @endcode
598
599 @par Exception Safety
600 Strong guarantee.
601
602 @throw std::logic_error if @ref set_headers was not called.
603
604 @throw std::length_error if there is insufficient internal buffer
605 space to start the operation.
606
607 @see
608 @ref set_headers.
609 */
610 BOOST_HTTP_PROTO_DECL
611 void
612 start();
613
614 /** Start serializing a message with a buffer sequence body.
615
616 This overload requires @ref set_headers to have
617 been called first.
618
619 At least one copy of the specified buffer sequence is maintained until
620 the serializer is done, gets reset, or is destroyed, after which all
621 of its copies are destroyed. Ownership of the underlying memory is not
622 transferred; the caller must ensure the memory remains valid until the
623 serializer's copies are destroyed.
624
625 @par Preconditions
626 @ref set_headers has been called and no @ref start
627 or @ref start_stream function has been called since.
628
629 @par Postconditions
630 @code
631 this->is_done() == false
632 @endcode
633
634 @par Constraints
635 @code
636 buffers::is_const_buffer_sequence_v<ConstBufferSequence> == true
637 @endcode
638
639 @par Exception Safety
640 Strong guarantee.
641
642 @throw std::logic_error if @ref set_headers was not called.
643
644 @throw std::length_error If there is insufficient internal buffer
645 space to start the operation.
646
647 @param buffers A buffer sequence containing the message body.
648
649 @see
650 @ref set_headers.
651 */
652 template<
653 class ConstBufferSequence,
654 class = typename std::enable_if<
655 buffers::is_const_buffer_sequence<
656 ConstBufferSequence>::value>::type
657 >
658 void
659 start(
660 ConstBufferSequence&& buffers);
661
662 /** Start serializing a message with a @em Source body.
663
664 This overload requires @ref set_headers to have
665 been called first.
666
667 The serializer destroys the Source object when:
668 @li `this->is_done() == true`
669 @li An unrecoverable serialization error occurs
670 @li The serializer is destroyed
671
672 @par Example
673 @code
674 file f("example.zip", file_mode::scan);
675 response.set_payload_size(f.size());
676 serializer.set_headers(response);
677 serializer.start<file_source>(std::move(f));
678 @endcode
679
680 @par Preconditions
681 @ref set_headers has been called and no @ref start
682 or @ref start_stream function has been called since.
683
684 @par Postconditions
685 @code
686 this->is_done() == false
687 @endcode
688
689 @par Constraints
690 @code
691 is_source<Source>::value == true
692 @endcode
693
694 @par Exception Safety
695 Strong guarantee.
696
697 @throw std::logic_error if @ref set_headers was not called.
698
699 @throw std::length_error if there is insufficient
700 internal buffer space to start the operation.
701
702 @param args Arguments to be passed to the
703 `Source` constructor.
704
705 @return A reference to the constructed Source object.
706
707 @see
708 @ref set_headers,
709 @ref source,
710 @ref file_source.
711 */
712 template<
713 class Source,
714 class Arg0,
715 class... Args,
716 class = typename std::enable_if<
717 is_source<Source>::value &&
718 !std::is_convertible<
719 Arg0,
720 message_base const&>::value>::type>
721 Source&
722 start(Arg0&& arg0, Args&&... args);
723
724 /** Start serializing a message with a @em Source body.
725
726 This overload requires @ref set_headers to have
727 been called first. This version takes no arguments
728 and default-constructs the Source.
729
730 @par Preconditions
731 @ref set_headers has been called and no @ref start
732 or @ref start_stream function has been called since.
733
734 @par Postconditions
735 @code
736 this->is_done() == false
737 @endcode
738
739 @par Constraints
740 @code
741 is_source<Source>::value == true
742 @endcode
743
744 @par Exception Safety
745 Strong guarantee.
746
747 @throw std::logic_error if @ref set_headers was not called.
748
749 @throw std::length_error if there is insufficient
750 internal buffer space to start the operation.
751
752 @return A reference to the constructed Source object.
753
754 @see
755 @ref set_headers,
756 @ref source.
757 */
758 template<
759 class Source,
760 class = typename std::enable_if<
761 is_source<Source>::value>::type>
762 Source&
763 start();
764
765 /** Start serializing a message using a stream interface.
766
767 This overload requires @ref set_headers to have
768 been called first.
769
770 Returns a @ref stream object for writing the body
771 data into the serializer's internal buffer.
772
773 Once the serializer is destroyed, @ref reset
774 is called, or @ref is_done returns true, the
775 only valid operation on the stream is destruction.
776
777 @par Example
778 @code
779 serializer.set_headers(response);
780 serializer::stream st = serializer.start_stream();
781 do
782 {
783 if(st.is_open())
784 {
785 std::size_t n = source.read_some(st.prepare());
786
787 if(ec == error::eof)
788 st.close();
789 else
790 st.commit(n);
791 }
792
793 write_some(client, serializer);
794
795 } while(!serializer.is_done());
796 @endcode
797
798 @par Preconditions
799 @ref set_headers has been called and no @ref start
800 or @ref start_stream function has been called since.
801
802 @par Postconditions
803 @code
804 this->is_done() == false
805 @endcode
806
807 @par Exception Safety
808 Strong guarantee.
809
810 @throw std::logic_error if @ref set_headers was not called.
811
812 @throw std::length_error if there is insufficient
813 internal buffer space to start the operation.
814
815 @return A @ref stream object for writing the body
816 data into the serializer's internal buffer.
817
818 @see
819 @ref set_headers,
820 @ref stream.
821 */
822 BOOST_HTTP_PROTO_DECL
823 stream
824 start_stream();
825
826 private:
827 class impl;
828 class cbs_gen;
829 template<class>
830 class cbs_gen_impl;
831
832 BOOST_HTTP_PROTO_DECL
833 detail::workspace&
834 ws();
835
836 BOOST_HTTP_PROTO_DECL
837 void
838 start_buffers_impl(
839 cbs_gen&);
840
841 BOOST_HTTP_PROTO_DECL
842 void
843 start_source_impl(
844 source&);
845
846 impl* impl_ = nullptr;
847 };
848
849 /** Serializer configuration settings.
850
851 @see
852 @ref install_serializer_service,
853 @ref serializer.
854 */
855 struct serializer::config
856 {
857 /** Enable Brotli Content-Encoding.
858
859 Requires `boost::capy::brotli::encode_service` to be
860 installed, otherwise an exception is thrown.
861 */
862 bool apply_brotli_encoder = false;
863
864 /** Enable Deflate Content-Encoding.
865
866 Requires `boost::zlib::deflate_service` to be
867 installed, otherwise an exception is thrown.
868 */
869 bool apply_deflate_encoder = false;
870
871 /** Enable Gzip Content-Encoding.
872
873 Requires `boost::zlib::deflate_service` to be
874 installed, otherwise an exception is thrown.
875 */
876 bool apply_gzip_encoder = false;
877
878 /** Brotli compression quality (0–11).
879
880 Higher values yield better but slower compression.
881 */
882 std::uint32_t brotli_comp_quality = 5;
883
884 /** Brotli compression window size (10–24).
885
886 Larger windows improve compression but increase
887 memory usage.
888 */
889 std::uint32_t brotli_comp_window = 18;
890
891 /** Zlib compression level (0–9).
892
893 0 = no compression, 1 = fastest, 9 = best
894 compression.
895 */
896 int zlib_comp_level = 6;
897
898 /** Zlib window bits (9–15).
899
900 Controls the history buffer size. Larger values
901 improve compression but use more memory.
902 */
903 int zlib_window_bits = 15;
904
905 /** Zlib memory level (1–9).
906
907 Higher values use more memory, but offer faster
908 and more efficient compression.
909 */
910 int zlib_mem_level = 8;
911
912 /** Minimum buffer size for payloads (must be > 0). */
913 std::size_t payload_buffer = 8192;
914
915 /** Reserved space for type-erasure storage.
916
917 Used for:
918 @li User-defined @ref source objects.
919 @li User-defined ConstBufferSequence instances.
920 */
921 std::size_t max_type_erase = 1024;
922 };
923
924 /** Install the serializer service.
925
926 @par Example
927 @code
928 // default configuration settings
929 install_serializer_service(ctx, {});
930
931 serializer sr(ctx);
932 @endcode
933
934 @par Exception Safety
935 Strong guarantee.
936
937 @throw std::invalid_argument If the service is
938 already installed on the context.
939
940 @param ctx Reference to the context on which
941 the service should be installed.
942
943 @param cfg Configuration settings for the
944 serializer.
945
946 @see
947 @ref serializer::config,
948 @ref serializer.
949 */
950 BOOST_HTTP_PROTO_DECL
951 void
952 install_serializer_service(
953 capy::polystore& ctx,
954 serializer::config const& cfg);
955
956 //------------------------------------------------
957
958 /** Used for streaming body data during serialization.
959
960 Provides an interface for supplying serialized
961 body content from an external source. This
962 object is returned by @ref
963 serializer::start_stream and enables
964 incremental writing of the message body into
965 the serializer's internal buffer.
966
967 The stream supports an inverted control flow
968 model, where the caller pushes body data as
969 needed.
970
971 Valid operations depend on the state of the
972 serializer. Once the serializer is destroyed,
973 reset, or completes, the stream becomes
974 invalid and must only be destroyed.
975
976 @see
977 @ref serializer::start_stream
978 */
979 class serializer::stream
980 {
981 public:
982 /** The type used to represent a sequence
983 of mutable buffers.
984 */
985 using mutable_buffers_type =
986 buffers::mutable_buffer_pair;
987
988 /** Constructor.
989
990 A default-constructed stream is
991 considered closed.
992
993 @par Postconditions
994 @code
995 this->is_open() == false
996 @endcode
997 */
998 stream() noexcept = default;
999
1000 /** Constructor.
1001
1002 After construction, the moved-from
1003 object is as if default-constructed.
1004
1005 @par Postconditions
1006 @code
1007 other->is_open() == false
1008 @endcode
1009
1010 @param other The object to move from.
1011 */
1012 stream(stream&& other) noexcept
1013 : impl_(other.impl_)
1014 {
1015 other.impl_ = nullptr;
1016 }
1017
1018 /** Move assignment.
1019
1020 After assignment, the moved-from
1021 object is as if default-constructed.
1022
1023 @par Postconditions
1024 @code
1025 other->is_open() == false
1026 @endcode
1027
1028 @param other The object to assign from.
1029 @return A reference to this object.
1030 */
1031 stream&
1032 operator=(stream&& other) noexcept
1033 {
1034 std::swap(impl_, other.impl_);
1035 return *this;
1036 }
1037
1038 /** Return true if the stream is open.
1039 */
1040 bool
1041 5062 is_open() const noexcept
1042 {
1043 5062 return impl_ != nullptr;
1044 }
1045
1046 /** Return the available capacity.
1047
1048 @par Preconditions
1049 @code
1050 this->is_open() == true
1051 @endcode
1052
1053 @par Exception Safety
1054 Strong guarantee.
1055
1056 @throw std::logic_error
1057 `this->is_open() == false`.
1058 */
1059 BOOST_HTTP_PROTO_DECL
1060 std::size_t
1061 capacity() const;
1062
1063 /** Prepare a buffer for writing.
1064
1065 Retuns a mutable buffer sequence representing
1066 the writable bytes. Use @ref commit to make the
1067 written data available to the serializer.
1068
1069 All buffer sequences previously obtained
1070 using @ref prepare are invalidated.
1071
1072 @par Preconditions
1073 @code
1074 this->is_open() == true && n <= this->capacity()
1075 @endcode
1076
1077 @par Exception Safety
1078 Strong guarantee.
1079
1080 @return An instance of @ref mutable_buffers_type
1081 the underlying memory is owned by the serializer.
1082
1083 @throw std::logic_error
1084 `this->is_open() == false`
1085
1086 @see
1087 @ref commit,
1088 @ref capacity.
1089 */
1090 BOOST_HTTP_PROTO_DECL
1091 mutable_buffers_type
1092 prepare();
1093
1094 /** Commit data to the serializer.
1095
1096 Makes `n` bytes available to the serializer.
1097
1098 All buffer sequences previously obtained
1099 using @ref prepare are invalidated.
1100
1101 @par Preconditions
1102 @code
1103 this->is_open() == true && n <= this->capacity()
1104 @endcode
1105
1106 @par Exception Safety
1107 Strong guarantee.
1108 Exceptions thrown on invalid input.
1109
1110 @param n The number of bytes to append.
1111
1112 @throw std::invalid_argument
1113 `n > this->capacity()`
1114
1115 @throw std::logic_error
1116 `this->is_open() == false`
1117
1118 @see
1119 @ref prepare,
1120 @ref capacity.
1121 */
1122 BOOST_HTTP_PROTO_DECL
1123 void
1124 commit(std::size_t n);
1125
1126 /** Close the stream if open.
1127
1128 Closes the stream and
1129 notifies the serializer that the
1130 message body has ended.
1131
1132 If the stream is already closed this
1133 call has no effect.
1134
1135 @par Postconditions
1136 @code
1137 this->is_open() == false
1138 @endcode
1139 */
1140 BOOST_HTTP_PROTO_DECL
1141 void
1142 close() noexcept;
1143
1144 /** Destructor.
1145
1146 Closes the stream if open.
1147 */
1148 24 ~stream()
1149 {
1150 24 close();
1151 24 }
1152
1153 private:
1154 friend class serializer;
1155
1156 explicit
1157 23 stream(serializer::impl* impl) noexcept
1158 23 : impl_(impl)
1159 {
1160 23 }
1161
1162 serializer::impl* impl_ = nullptr;
1163 };
1164
1165 } // http_proto
1166 } // boost
1167
1168 #include <boost/http_proto/impl/serializer.hpp>
1169
1170 #endif
1171