Skip to content

Commit c7401aa

Browse files
MungoGclaude
andcommitted
feat: separate set_headers from start functions in serializer
Add new API to set message headers separately from starting serialization. This allows setting headers once and then choosing the body style (empty, buffers, source, or stream) in a second step. New public methods: - set_headers(message_base const&) - start() - empty body - start(ConstBufferSequence&&) - buffer sequence body - start<Source>(Args&&...) - source body - start_stream() - stream body The original start functions that take message_base remain for backward compatibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3f1c215 commit c7401aa

File tree

3 files changed

+626
-0
lines changed

3 files changed

+626
-0
lines changed

include/boost/http_proto/impl/serializer.hpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,24 @@ start(
132132
std::forward<ConstBufferSequence>(cbs)));
133133
}
134134

135+
template<
136+
class ConstBufferSequence,
137+
class>
138+
void
139+
serializer::
140+
start(
141+
ConstBufferSequence&& cbs)
142+
{
143+
static_assert(buffers::is_const_buffer_sequence<
144+
ConstBufferSequence>::value,
145+
"ConstBufferSequence type requirements not met");
146+
147+
start_buffers_impl(
148+
ws().emplace<cbs_gen_impl<typename
149+
std::decay<ConstBufferSequence>::type>>(
150+
std::forward<ConstBufferSequence>(cbs)));
151+
}
152+
135153
template<
136154
class Source,
137155
class... Args,
@@ -156,6 +174,50 @@ start(
156174
return source;
157175
}
158176

177+
template<
178+
class Source,
179+
class Arg0,
180+
class... Args,
181+
class>
182+
Source&
183+
serializer::
184+
start(
185+
Arg0&& arg0,
186+
Args&&... args)
187+
{
188+
static_assert(
189+
!std::is_abstract<Source>::value, "");
190+
static_assert(
191+
std::is_constructible<Source, Arg0, Args...>::value ||
192+
std::is_constructible<Source, detail::workspace&, Arg0, Args...>::value,
193+
"The Source cannot be constructed with the given arguments");
194+
195+
auto& source = ws().emplace<Source>(
196+
std::forward<Arg0>(arg0),
197+
std::forward<Args>(args)...);
198+
start_source_impl(source);
199+
return source;
200+
}
201+
202+
template<
203+
class Source,
204+
class>
205+
Source&
206+
serializer::
207+
start()
208+
{
209+
static_assert(
210+
!std::is_abstract<Source>::value, "");
211+
static_assert(
212+
std::is_default_constructible<Source>::value ||
213+
std::is_constructible<Source, detail::workspace&>::value,
214+
"The Source cannot be default-constructed");
215+
216+
auto& source = ws().emplace<Source>();
217+
start_source_impl(source);
218+
return source;
219+
}
220+
159221
} // http_proto
160222
} // boost
161223

include/boost/http_proto/serializer.hpp

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,279 @@ class serializer
534534
bool
535535
is_done() const noexcept;
536536

537+
/** Set the message headers for serialization.
538+
539+
This function prepares the serializer with the
540+
HTTP start-line and headers from `m`. After
541+
calling this function, one of the @ref start
542+
or @ref start_stream overloads that do not
543+
take a message parameter must be called to
544+
begin serialization.
545+
546+
Changing the contents of the message after
547+
calling this function and before @ref is_done
548+
returns `true` results in undefined behavior.
549+
550+
@par Preconditions
551+
@code
552+
this->is_done() == true
553+
@endcode
554+
555+
@par Exception Safety
556+
Strong guarantee.
557+
558+
@throw std::logic_error `this->is_done() == false`.
559+
560+
@param m The request or response headers to serialize.
561+
562+
@see
563+
@ref message_base.
564+
*/
565+
BOOST_HTTP_PROTO_DECL
566+
void
567+
set_headers(message_base const& m);
568+
569+
/** Start serializing a message with an empty body.
570+
571+
This overload requires @ref set_headers to have
572+
been called first.
573+
574+
@par Preconditions
575+
@ref set_headers has been called and no @ref start
576+
or @ref start_stream function has been called since.
577+
578+
@par Postconditions
579+
@code
580+
this->is_done() == false
581+
@endcode
582+
583+
@par Exception Safety
584+
Strong guarantee.
585+
586+
@throw std::logic_error if @ref set_headers was not called.
587+
588+
@throw std::length_error if there is insufficient internal buffer
589+
space to start the operation.
590+
591+
@see
592+
@ref set_headers.
593+
*/
594+
BOOST_HTTP_PROTO_DECL
595+
void
596+
start();
597+
598+
/** Start serializing a message with a buffer sequence body.
599+
600+
This overload requires @ref set_headers to have
601+
been called first.
602+
603+
At least one copy of the specified buffer sequence is maintained until
604+
the serializer is done, gets reset, or is destroyed, after which all
605+
of its copies are destroyed. Ownership of the underlying memory is not
606+
transferred; the caller must ensure the memory remains valid until the
607+
serializer's copies are destroyed.
608+
609+
@par Preconditions
610+
@ref set_headers has been called and no @ref start
611+
or @ref start_stream function has been called since.
612+
613+
@par Postconditions
614+
@code
615+
this->is_done() == false
616+
@endcode
617+
618+
@par Constraints
619+
@code
620+
buffers::is_const_buffer_sequence_v<ConstBufferSequence> == true
621+
@endcode
622+
623+
@par Exception Safety
624+
Strong guarantee.
625+
626+
@throw std::logic_error if @ref set_headers was not called.
627+
628+
@throw std::length_error If there is insufficient internal buffer
629+
space to start the operation.
630+
631+
@param buffers A buffer sequence containing the message body.
632+
633+
@see
634+
@ref set_headers.
635+
*/
636+
template<
637+
class ConstBufferSequence,
638+
class = typename std::enable_if<
639+
buffers::is_const_buffer_sequence<
640+
ConstBufferSequence>::value>::type
641+
>
642+
void
643+
start(
644+
ConstBufferSequence&& buffers);
645+
646+
/** Start serializing a message with a @em Source body.
647+
648+
This overload requires @ref set_headers to have
649+
been called first.
650+
651+
The serializer destroys the Source object when:
652+
@li `this->is_done() == true`
653+
@li An unrecoverable serialization error occurs
654+
@li The serializer is destroyed
655+
656+
@par Example
657+
@code
658+
file f("example.zip", file_mode::scan);
659+
response.set_payload_size(f.size());
660+
serializer.set_headers(response);
661+
serializer.start<file_source>(std::move(f));
662+
@endcode
663+
664+
@par Preconditions
665+
@ref set_headers has been called and no @ref start
666+
or @ref start_stream function has been called since.
667+
668+
@par Postconditions
669+
@code
670+
this->is_done() == false
671+
@endcode
672+
673+
@par Constraints
674+
@code
675+
is_source<Source>::value == true
676+
@endcode
677+
678+
@par Exception Safety
679+
Strong guarantee.
680+
681+
@throw std::logic_error if @ref set_headers was not called.
682+
683+
@throw std::length_error if there is insufficient
684+
internal buffer space to start the operation.
685+
686+
@param args Arguments to be passed to the
687+
`Source` constructor.
688+
689+
@return A reference to the constructed Source object.
690+
691+
@see
692+
@ref set_headers,
693+
@ref source,
694+
@ref file_source.
695+
*/
696+
template<
697+
class Source,
698+
class Arg0,
699+
class... Args,
700+
class = typename std::enable_if<
701+
is_source<Source>::value &&
702+
!std::is_convertible<
703+
Arg0,
704+
message_base const&>::value>::type>
705+
Source&
706+
start(Arg0&& arg0, Args&&... args);
707+
708+
/** Start serializing a message with a @em Source body.
709+
710+
This overload requires @ref set_headers to have
711+
been called first. This version takes no arguments
712+
and default-constructs the Source.
713+
714+
@par Preconditions
715+
@ref set_headers has been called and no @ref start
716+
or @ref start_stream function has been called since.
717+
718+
@par Postconditions
719+
@code
720+
this->is_done() == false
721+
@endcode
722+
723+
@par Constraints
724+
@code
725+
is_source<Source>::value == true
726+
@endcode
727+
728+
@par Exception Safety
729+
Strong guarantee.
730+
731+
@throw std::logic_error if @ref set_headers was not called.
732+
733+
@throw std::length_error if there is insufficient
734+
internal buffer space to start the operation.
735+
736+
@return A reference to the constructed Source object.
737+
738+
@see
739+
@ref set_headers,
740+
@ref source.
741+
*/
742+
template<
743+
class Source,
744+
class = typename std::enable_if<
745+
is_source<Source>::value>::type>
746+
Source&
747+
start();
748+
749+
/** Start serializing a message using a stream interface.
750+
751+
This overload requires @ref set_headers to have
752+
been called first.
753+
754+
Returns a @ref stream object for writing the body
755+
data into the serializer's internal buffer.
756+
757+
Once the serializer is destroyed, @ref reset
758+
is called, or @ref is_done returns true, the
759+
only valid operation on the stream is destruction.
760+
761+
@par Example
762+
@code
763+
serializer.set_headers(response);
764+
serializer::stream st = serializer.start_stream();
765+
do
766+
{
767+
if(st.is_open())
768+
{
769+
std::size_t n = source.read_some(st.prepare());
770+
771+
if(ec == error::eof)
772+
st.close();
773+
else
774+
st.commit(n);
775+
}
776+
777+
write_some(client, serializer);
778+
779+
} while(!serializer.is_done());
780+
@endcode
781+
782+
@par Preconditions
783+
@ref set_headers has been called and no @ref start
784+
or @ref start_stream function has been called since.
785+
786+
@par Postconditions
787+
@code
788+
this->is_done() == false
789+
@endcode
790+
791+
@par Exception Safety
792+
Strong guarantee.
793+
794+
@throw std::logic_error if @ref set_headers was not called.
795+
796+
@throw std::length_error if there is insufficient
797+
internal buffer space to start the operation.
798+
799+
@return A @ref stream object for writing the body
800+
data into the serializer's internal buffer.
801+
802+
@see
803+
@ref set_headers,
804+
@ref stream.
805+
*/
806+
BOOST_HTTP_PROTO_DECL
807+
stream
808+
start_stream();
809+
537810
private:
538811
class impl;
539812
class cbs_gen;
@@ -549,18 +822,36 @@ class serializer
549822
start_init(
550823
message_base const&);
551824

825+
BOOST_HTTP_PROTO_DECL
826+
void
827+
start_empty_impl();
828+
552829
BOOST_HTTP_PROTO_DECL
553830
void
554831
start_buffers(
555832
message_base const&,
556833
cbs_gen&);
557834

835+
BOOST_HTTP_PROTO_DECL
836+
void
837+
start_buffers_impl(
838+
cbs_gen&);
839+
558840
BOOST_HTTP_PROTO_DECL
559841
void
560842
start_source(
561843
message_base const&,
562844
source&);
563845

846+
BOOST_HTTP_PROTO_DECL
847+
void
848+
start_source_impl(
849+
source&);
850+
851+
BOOST_HTTP_PROTO_DECL
852+
stream
853+
start_stream_impl();
854+
564855
impl* impl_ = nullptr;
565856
};
566857

0 commit comments

Comments
 (0)