Flow-IPC 1.0.1
Flow-IPC project: Full implementation reference.
heap_serializer.hpp
Go to the documentation of this file.
1/* Flow-IPC: Structured Transport
2 * Copyright (c) 2023 Akamai Technologies, Inc.; and other contributors.
3 * Each commit is copyright by its respective author or author's employer.
4 *
5 * Licensed under the MIT License:
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE. */
24
25/// @file
26#pragma once
27
30#include "ipc/util/util_fwd.hpp"
31#include <flow/error/error.hpp>
32#include <boost/move/make_unique.hpp>
33
35{
36
37// Types.
38
39/**
40 * Value for Struct_builder::Session when no extra information is needed when serializing Struct_builder for
41 * subsequent sending to another process.
42 *
43 * @see Struct_builder::Session concept.
44 */
45struct Null_session {};
46
47/**
48 * Implements Struct_builder concept by straightforwardly allocating fixed-size segments on-demand in
49 * the regular heap and serializing directly inside those segments. That is, each mutation via payload_msg_builder()
50 * may, as needed, trigger a `malloc()` (or similar) of size N passed to the ctor of Heap_fixed_builder; and
51 * each buffer returned by emit_serialization() will be of size N or less.
52 *
53 * ### Failure mode ###
54 * As long as each leaf capnp object set via mutation of payload_msg_builder() can be serialized in N bytes or fewer,
55 * emit_serialization() shall succeed. For fixed-size leaves this is generally not a problem; for reasonable N
56 * in the KiB, things such as integers and enumerations won't be a problem. However for variable-size
57 * objects, particularly strings and blobs and lists and the like, it can be easy to exceed N. In this case,
58 * even though internally the problem could be detected at mutation time, it will be reported
59 * in the next emit_serialization() call (as mandated by the concept API). Specifically
60 * error::Code::S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG shall be emitted. See "Reasonable uses" below for
61 * discussion on avoiding this fate.
62 *
63 * ### Reasonable uses ###
64 * This is suitable for transmission via a Blob_sender (or Native_handle_sender) wherein each blob (or meta-blob,
65 * respectively) sent has either a hard size limit (meaning a Blob_sender::send_blob() or
66 * Native_handle_sender::send_native_handle() call will fail if this limit is exceeded) or an effective limit
67 * (meaning transmission performance is poor in the same event). Indeed the use cases that informed this strategy
68 * were:
69 * - Blob_stream_mq_sender::send_blob() shall fail if `blob.size() >= N`, where `N` is the message size limit
70 * passed to its ctor.
71 * - `Native_socket_stream::send_*()` shall fail if
72 * `blob.size() >= sync_io::Native_socket_stream::S_MAX_META_BLOB_LENGTH`.
73 * - Moreover Native_socket_stream informally is documented to feature good performance compared to
74 * the MQ-based streams when not exceeding the "10s-of-KiB range" (quoting its doc header as of this writing).
75 *
76 * In "Failure mode" above we pointed out an immediate danger if one uses Heap_fixed_builder to naively serialize
77 * arbitrary user-supplied schemas. Simply put, if one mutates payload_msg_builder() in such a
78 * way as to introduce a big leaf, such as a large image blob,
79 * then emit_serialization()) will emit error::Code::S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG; and that's the end
80 * of that.
81 *
82 * Even if one avoids this somehow -- let's say by always fragmenting large things into smaller-size leaves
83 * (itself undesirable: the point of serialization of structured data is to not have to worry about data representation
84 * at the application level) -- this can lead to, well, a fragmented representation, inefficiently using each N-sized
85 * segment with too much unused space. So what to do?
86 *
87 * One could write a builder similar to Heap_fixed_builder minus the `_fixed` part; certainly capnp
88 * supplies the tools needed to simply allocate large-enough segments (internally, a `capnp::MallocMessageBuilder`-like
89 * `MessageBuilder` is used already; we'd just need to use different
90 * knob values on `MallocMessageBuilder` or similar and be less draconian in what segment sizes
91 * emit_serialization()) will allow). Of course then the transport mechanism used for the resulting segments would need
92 * to be able to handle larger blobs. Blob_stream_mq_sender already supports larger max message sizes, and
93 * Native_socket_stream with a larger or variable `S_MAX_META_BLOB_LENGTH` could be written. Or even without
94 * that one could split any too-large segments across multiple blobs. However that's
95 * hardly consolation in practice: too much RAM use could result; and/or the copying involved would eventually
96 * prove too expensive. So... probably the non-`_fixed`/multi-blob-segment approaches are not good enough,
97 * at least not in general. So what to do?
98 *
99 * At least one approach is to use a 2-layer approach. The true serialization of the user's schema could
100 * be placed in SHared Memory (SHM). Then only a handle (or handles) to this SHM-stored serialization could
101 * be transmitted via Heap_fixed_builder; even a *single* segment of small size would be enough to transmit
102 * as much, as each handle is (more or less) a pointer. Although the SHM-based builder (documented elsewhere)
103 * would be the one used at the higher level, internally it would leverage Heap_fixed_builder to transmit the
104 * handle(s) to SHM.
105 *
106 * Hence Heap_fixed_builder remains of use; but keep in mind the above limitations and (at least its original)
107 * intended use.
108 *
109 * The above discussion is a more specific treatment of the outer-serialization/inner-serialization discussion
110 * in the Struct_builder concept doc header.
111 *
112 * @internal
113 * ### Implementation ###
114 * If one is familiar with capnp, then one can probably quickly guess how this class template accomplishes
115 * what it promises in just the brief summary at the top of this doc header:
116 * Heap_fixed_builder_capnp_message_builder is what we use internally; it's like `MallocMessageBuilder`
117 * but (1) mandates the equivalent of `AllocationStrategy::FIXED_SIZE` always and (2) has support
118 * for a framing prefix and postfix coexisting within each allocated buffer per segment
119 * (per our ctor args). As it must, that builder (like `MallocMessageBuilder`) is documented
120 * to allocate a larger-than-N segment if necessary to encode a particular too-large leaf.
121 * We do not stop this in and of itself; but emit_serialization() simply refuses to return this resulting serialization,
122 * if it detects than indeed such a segment had to be allocated during preceding payload_msg_builder() mutations.
123 * So `*this` will allocate and eat the needed RAM; but it simply will refuse to return it `public`ly.
124 * @endinternal
125 *
126 * @see Heap_reader
127 * Counterpart Struct_reader implementation that can deserialize data that this has serialized.
128 * @see Struct_builder: implemented concept.
129 */
131 public flow::log::Log_context
132{
133public:
134 // Types.
135
136 /**
137 * Implements Struct_builder::Config sub-concept. In this impl: The data members control Heap_fixed_builder's
138 * behavior as follows:
139 *
140 * Heap_fixed_builder ctor configured by Config creates builder that shall heap-allocate segments of the given size on
141 * demand subsequently. A successful Heap_fixed_builder::emit_serialization() call shall return individual
142 * segment sizes never exceeding #m_segment_sz (for the [`begin()`, `end()`) area), with
143 * `start() == #m_frame_prefix_sz`, and with `capacity() - start() - size() >= #m_frame_postfix_sz`.
144 *
145 * However, internally, larger segments may still be allocated, namely if a Heap_fixed_builder::payload_msg_builder()
146 * mutation supplies a too-large leaf -- but, if this occurs, Heap_fixed_builder::emit_serialization() shall
147 * emit an error and no successful serialization. That said be aware you'll still be charged for the resulting
148 * RAM use in the meantime. Informal recommendations:
149 * - Do not use Heap_fixed_builder if this is a danger given the schema in question.
150 * See Heap_fixed_builder doc header for discussion of alternative approaches.
151 * - If the problem does occur (Heap_fixed_builder::emit_serialization() does emit the error) nevertheless,
152 * it is pointless to keep using `*this`; destroy it and take the appropriate exceptional-error-contingency steps.
153 */
154 struct Config
155 {
156 // Types.
157
158 /// Implements concept API.
160
161 // Data.
162
163 /// Logger to use for logging subsequently.
164 flow::log::Logger* m_logger_ptr;
165 /// See `struct` doc header.
167 /// See `struct` doc header.
169 /// See `struct` doc header.
171 }; // class Config
172
173 /**
174 * Implements concept API. This being a non-zero-copy Struct_builder, no information is needed for
175 * emit_serialization() beyond the payload itself.
176 */
178
179 // Constructors/destructor.
180
181 /**
182 * Implements concept API.
183 * @see Struct_builder::Struct_builder(): implemented concept.
184 */
186
187 /**
188 * Implements concept API. See Config doc header for information on how `*this` behavior is controlled by `config`.
189 *
190 * @param config
191 * See above.
192 *
193 * @see Struct_builder::Struct_builder(): implemented concept.
194 */
195 explicit Heap_fixed_builder(const Config& config);
196
197 /// Disallow copy construction.
199
200 /**
201 * Implements concept API.
202 *
203 * @param src
204 * See above.
205 *
206 * @see Struct_builder::Struct_builder(): implemented concept.
207 */
209
210 /**
211 * Implements concept API. In this impl: frees all segments allocated on-demand so far.
212 * @see Struct_builder::~Struct_builder(): implemented concept.
213 */
215
216 // Methods.
217
218 /// Disallow copy assignment.
220
221 /**
222 * Implements concept API.
223 *
224 * @param src
225 * See above.
226 * @return See above.
227 *
228 * @see Struct_builder::Struct_builder(): implemented concept.
229 */
231
232 /**
233 * Implements concept API.
234 *
235 * @return See above.
236 *
237 * @see Struct_builder::payload_msg_builder(): implemented concept.
238 */
240
241 /**
242 * Implements concept API.
243 *
244 * ### Errors ###
245 * As discussed in class doc header, you should be on guard for the particular error
246 * error::Code::S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG. See class doc header for discussion on how to avoid
247 * it. As of this writing no other failure modes exist.
248 *
249 * @param target_blobs
250 * See above. Also recall (see ctor) that for each returned `blob`:
251 * individual segment sizes shall never exceed
252 * Config::m_segment_sz (for the [`begin()`, `end()`) area), with `start() == m_frame_prefix_sz`, and
253 * with `capacity() - start() - size() >= m_frame_postfix_sz`.
254 * @param session
255 * See above. In this case the proper value is `NULL_SESSION`.
256 * @param err_code
257 * See above. #Error_code generated: error::Code::S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG (a previous
258 * mutation introduced a leaf whose serialization would necessitate allocating a segment exceeding
259 * Config::m_segment_sz -- see ctor -- in size).
260 *
261 * @see Struct_builder::emit_serialization(): implemented concept.
262 */
263 void emit_serialization(Segment_ptrs* target_blobs, const Session& session, Error_code* err_code = 0) const;
264
265 /**
266 * Implements concept API.
267 *
268 * @return See above.
269 *
270 * @see Struct_builder::n_serialization_segments(): implemented concept.
271 */
272 size_t n_serialization_segments() const;
273
274private:
275 // Types.
276
277 /// Alias for the capnp `MallocMessageBuilder`-like serialization engine of ours.
279
280 // Data.
281
282 /// See ctor. We only store it to be able to emit `S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG` in emit_serialization().
284
285 /**
286 * The capnp builder engine which really does the work including owning the needed allocated segments so far.
287 * payload_msg_builder() simply returns (up-cast of) `&m_engine`.
288 *
289 * ### Why the `unique_ptr` wrapper? ###
290 * This is subtler than it appears: We need to be move-ctible and move-assignable; and #m_engine therefore
291 * does too -- and in fact #Capnp_heap_engine *is*. So the `unique_ptr` wrapping appears superfluous and a
292 * waste of compute and space at least. However, see the note on move-ctibility/assignability in
293 * Heap_fixed_builder_capnp_message_builder doc header: It *is* those things, because super-class
294 * (interface) #Capnp_msg_builder_interface is, but any #Capnp_msg_builder_interface sub-class's move (if available)
295 * has to copy ~200 bytes at least. Whether the extra alloc/dealloc is better than a copy of that length is a
296 * bit questionable, but we suspect it is at least somewhat better.
297 *
298 * As a side benefit: it's an easy way to detect a moved-from `*this` and `assert()` in some situations.
299 */
300 boost::movelib::unique_ptr<Capnp_heap_engine> m_engine;
301}; // class Heap_fixed_builder
302
303/**
304 * Implements Struct_reader concept by straightforwardly interpreting a serialization by Heap_fixed_builder
305 * or any other builder that produces segments directly readable via `SegmentArrayMessageReader`.
306 *
307 * While written originally specificaly as the counterpart to Heap_fixed_builder, it would work with any
308 * builder that produces an equivalent serialization modulo using potentially different segment sizes.
309 * That is why it is called `Heap_reader` -- not `Heap_reader`.
310 *
311 * The most important thing to recognize about Heap_reader: add_serialization_segment() -- which is required
312 * (by the concept) to acquire and return memory segments of the size requested by the user -- shall allocate
313 * a new `Blob` of the specified size in regular heap (via `new[]`, that is).
314 *
315 * ### Possible futher impls that would iterate upon Heap_reader ###
316 * See Struct_reader "Allocation and perf" doc header section. It discusses, indirectly, ideas for
317 * other reader impls that would be compatible with Heap_fixed_builder (and equivalents) but that
318 * would obtain from sources other than `new`ing in regular heap. E.g.: fixed reused `Blob`; pool allocation.
319 *
320 * @see Heap_fixed_builder
321 * A counterpart Struct_builder implementation that can create compatible serializations.
322 * @see Struct_reader: implemented concept.
323 */
325 public flow::log::Log_context,
326 private boost::noncopyable
327{
328public:
329 // Types.
330
331 /// Implements Struct_reader::Config sub-concept.
332 struct Config
333 {
334 // Types.
335
336 /// Implements concept API.
338
339 // Data.
340
341 /// Logger to use for logging subsequently.
342 flow::log::Logger* m_logger_ptr;
343
344 /**
345 * Best guess for how many times you expect to call add_serialization_segment(); or 0 if you have no guess.
346 * This is a (fairly minor as of this writing) optimization opportunity; an internal container may be
347 * `reserve()`d preventing future reallocs.
348 */
350 }; // class Config
351
352 // Constructors/destructor.
353
354 /**
355 * Implements concept API. See Config doc header for information on how `*this` behavior is controlled by `config`.
356 *
357 * @param config
358 * See above.
359 *
360 * @see Struct_reader::Struct_reader(): implemented concept.
361 */
362 explicit Heap_reader(const Config& config);
363
364 /**
365 * Implements concept API. In this impl: frees all segments allocated via add_serialization_segment() so far.
366 * @see Struct_reader::~Struct_reader(): implemented concept.
367 */
368 ~Heap_reader();
369
370 // Methods.
371
372 /**
373 * Implements concept API. Reminder: you must `.resize()` the returned `Blob` in-place to indicate the
374 * size of the actual segment (and possibly omitting prefix or postfix frame data), before attempting
375 * deserialization().
376 *
377 * @param max_sz
378 * See above.
379 * @return See above. Note: This impl never returns null. However any code relying on the concept
380 * Struct_reader, and not this specific impl (Heap_reader), should naturally refrain
381 * from relying on this fact. Struct_reader::add_serialization_segment() may return null.
382 *
383 * @see Struct_reader::add_serialization_segment(): implemented concept.
384 */
385 flow::util::Blob* add_serialization_segment(size_t max_sz);
386
387 /**
388 * Implements concept API.
389 *
390 * @tparam Struct
391 * See above.
392 * @param err_code
393 * See above. #Error_code generated:
394 * error::Code::S_DESERIALIZE_FAILED_INSUFFICIENT_SEGMENTS (add_serialization_segment() was never called),
395 * error::Code::S_DESERIALIZE_FAILED_SEGMENT_MISALIGNED (add_serialization_segment()-returned segment
396 * was modified subsequently to start at a misaligned address).
397 * @return See above.
398 *
399 * @see Struct_reader::deserialization(): implemented concept.
400 */
401 template<typename Struct>
402 typename Struct::Reader deserialization(Error_code* err_code = 0);
403
404private:
405 // Types.
406
407 /// Alias for the capnp `SegmentArrayMessageReader` deserialization engine.
408 using Capnp_heap_engine = ::capnp::SegmentArrayMessageReader;
409
410 /// Alias to pointer to #Capnp_heap_engine.
411 using Capnp_heap_engine_ptr = boost::movelib::unique_ptr<Capnp_heap_engine>;
412
413 /**
414 * Alias to capnp type that's similar to `boost::asio::const_buffer` but stores `word*` and `word` count
415 * instead of `uint8_t*` and byte count.
416 */
417 using Capnp_word_array_ptr = kj::ArrayPtr<const ::capnp::word>;
418
419 // Data.
420
421 /**
422 * The actual serialization supplied so far, as divided up into segments (`Blob`s -- byte arrays).
423 * Before the first add_serialization_segment(): empty.
424 * After that but before deserialization(): Each `Blob`, except possibly the last, is finalized.
425 * At entry to deserialization() or later: Each `Blob` is finalized.
426 */
427 std::vector<boost::movelib::unique_ptr<flow::util::Blob>> m_serialization_segments;
428
429 /**
430 * After deserialization(), capnp-targeted data structure which is essentially `vector<>` of each
431 * `Blob::const_buffer()` from #m_serialization_segments, in order, except instead of a given `const_buffer`
432 * it's the capnp-style data structure that stores a `word*` and `word` count (instead of
433 * `uint8_t*` and byte count). This must be alive while #m_engine is non-null, so from deserialization() on;
434 * capnp's #m_engine saves the pointer `&m_capnp_segments[0]` and `m_capnp_segments.size()`.
435 */
436 std::vector<Capnp_word_array_ptr> m_capnp_segments;
437
438 /**
439 * The capnp reader engine, as set in the deserialization() call and corresponding to the
440 * `Struct::Reader` it returned; or null if deserialization() has not yet been called. In terms of data this, really,
441 * just stores pointers into the backing serialization -- the blobs #m_serialization_segments.
442 * deserialization()-returned value then adds the capnp structured-data accessors which hop around those segments,
443 * obtaining individual values directly from the segment blobs #m_serialization_segments.
444 */
446}; // class Heap_reader
447
448/**
449 * Convenience alias: Use this when constructing a struc::Channel with tag
450 * Channel_base::S_SERIALIZE_VIA_HEAP.
451 *
452 * See Channel_base::Serialize_via_heap doc header for when/how to use.
453 *
454 * Tip: `Sync_io_obj` member alias will get you the `sync_io`-pattern counterpart.
455 *
456 * @internal
457 * Unable to put it in ..._fwd.hpp, because it relies on nested class inside incomplete type.
458 */
459template<typename Channel_obj, typename Message_body>
461 = Channel<Channel_obj, Message_body,
463
464// Free functions: in *_fwd.hpp.
465
466// Template implementations.
467
468template<typename Struct>
470{
471 using flow::error::Runtime_error;
472 using flow::util::buffers_dump_string;
473 using boost::movelib::make_unique;
474 using std::vector;
475 using ::capnp::word;
476 using Capnp_word_array_array_ptr = kj::ArrayPtr<const Capnp_word_array_ptr>;
477 using Capnp_struct_reader = typename Struct::Reader;
478 using Capnp_heap_engine_opts = ::capnp::ReaderOptions;
479
480 // See explanation and associated to-do in shm::Reader::deserialization(); applies equally here.
481 constexpr Capnp_heap_engine_opts RDR_OPTIONS = { std::numeric_limits<uint64_t>::max() / sizeof(word),
482 Capnp_heap_engine_opts{}.nestingLimit };
483
484 // Helper to emit error via usual semantics. We return a ref so can't use FLOW_ERROR_EXEC_AND_THROW_ON_ERROR().
485 const auto emit_error = [&](const Error_code& our_err_code) -> Capnp_struct_reader
486 {
487 if (err_code)
488 {
489 *err_code = our_err_code;
490 return Capnp_struct_reader();
491 }
492 // else
493 throw Runtime_error(our_err_code, "Heap_reader::deserialization()");
494 return Capnp_struct_reader(); // Doesn't get here.
495 };
496
497 if (m_serialization_segments.empty())
498 {
500 }
501 // else: OK so far.
502
503 assert((!m_engine) && "Do not call deserialization() more than once.");
504
505 // Set up capnp ArrayPtr<ArrayPtr>. ArrayPtr is a ptr (to word) + size (in `word`s). The backing vector:
506 auto& capnp_segs = m_capnp_segments;
507 assert(m_capnp_segments.empty() && "m_capnp_segments should have been empty so far, pre-deserialization().");
508 capnp_segs.reserve(m_serialization_segments.size());
509
510 size_t idx = 0;
511 for (const auto& serialization_segment : m_serialization_segments)
512 {
513 const auto data_ptr = serialization_segment->const_data();
514 const auto seg_size = serialization_segment->size();
515
516 if ((uintptr_t(data_ptr) % sizeof(void*)) != 0)
517 {
518 FLOW_LOG_WARNING("Heap_reader [" << *this << "]: "
519 "Serialization segment [" << idx << "] "
520 "(0 based, of [" << m_serialization_segments.size() << "], 1-based): "
521 "Heap buffer @[" << static_cast<const void*>(data_ptr) << "] sized [" << seg_size << "]: "
522 "Starting pointer is not this-architecture-word-aligned. Bug? Misuse of Heap_reader? "
523 "Misalignment is against the API use requirements; capnp would complain and fail.");
525 }
526 // else
527
528 FLOW_LOG_TRACE("Heap_reader [" << *this << "]: "
529 "Serialization segment [" << idx << "] "
530 "(0 based, of [" << m_serialization_segments.size() << "], 1-based): "
531 "Heap buffer @[" << static_cast<const void*>(data_ptr) << "] sized [" << seg_size << "]: "
532 "Feeding into capnp deserialization engine.");
533 FLOW_LOG_DATA("Segment contents: "
534 "[\n" << buffers_dump_string(serialization_segment->const_buffer(), " ") << "].");
535
536 capnp_segs.emplace_back(reinterpret_cast<const word*>(data_ptr), // uint8_t* -> word* = OK given C++ aliasing rules.
537 seg_size / sizeof(word)); // @todo Maybe also check that seg_size is a multiple? assert()?
538
539 ++idx;
540 } // for (const auto& serialization_segment : m_serialization_segments)
541
542 /* Initialize the deserialization engine by giving it the pointers to/size of the backing segment blobs.
543 * It doesn't copy this array of pointers/sizes, so that array must stay alive, hence why capnp_segs is
544 * really m_capnp_segments. To be clear: not only must the blobs stay alive but so must the array referring
545 * to them. */
546 const Capnp_word_array_array_ptr capnp_segs_ptr(&(capnp_segs.front()), capnp_segs.size());
547 m_engine = make_unique<Capnp_heap_engine>(capnp_segs_ptr, RDR_OPTIONS);
548
549 if (err_code)
550 {
551 err_code->clear();
552 }
553
554 // And lastly set up the structured-accessor API object that'll traverse those blobs via that engine.
555 return m_engine->getRoot<Struct>();
556} // Heap_reader::deserialization()
557
558} // namespace ipc::transport::struc
Owning and wrapping a pre-connected transport::Channel peer (an endpoint of an established channel ov...
Definition: channel.hpp:589
A capnp::MessageBuilder used by Heap_fixed_builder: similar to a capnp::MallocMessageBuilder with the...
Implements Struct_builder concept by straightforwardly allocating fixed-size segments on-demand in th...
Capnp_msg_builder_interface * payload_msg_builder()
Implements concept API.
size_t n_serialization_segments() const
Implements concept API.
Heap_fixed_builder & operator=(Heap_fixed_builder &&src)
Implements concept API.
Heap_fixed_builder(const Heap_fixed_builder &)=delete
Disallow copy construction.
Heap_fixed_builder()
Implements concept API.
boost::movelib::unique_ptr< Capnp_heap_engine > m_engine
The capnp builder engine which really does the work including owning the needed allocated segments so...
void emit_serialization(Segment_ptrs *target_blobs, const Session &session, Error_code *err_code=0) const
Implements concept API.
~Heap_fixed_builder()
Implements concept API.
Heap_fixed_builder & operator=(const Heap_fixed_builder &)=delete
Disallow copy assignment.
Heap_fixed_builder(Heap_fixed_builder &&src)
Implements concept API.
size_t m_segment_sz
See ctor. We only store it to be able to emit S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG in emit_seriali...
Implements Struct_reader concept by straightforwardly interpreting a serialization by Heap_fixed_buil...
Struct::Reader deserialization(Error_code *err_code=0)
Implements concept API.
Heap_reader(const Config &config)
Implements concept API.
boost::movelib::unique_ptr< Capnp_heap_engine > Capnp_heap_engine_ptr
Alias to pointer to Capnp_heap_engine.
std::vector< boost::movelib::unique_ptr< flow::util::Blob > > m_serialization_segments
The actual serialization supplied so far, as divided up into segments (Blobs – byte arrays).
~Heap_reader()
Implements concept API.
::capnp::SegmentArrayMessageReader Capnp_heap_engine
Alias for the capnp SegmentArrayMessageReader deserialization engine.
flow::util::Blob * add_serialization_segment(size_t max_sz)
Implements concept API.
Capnp_heap_engine_ptr m_engine
The capnp reader engine, as set in the deserialization() call and corresponding to the Struct::Reader...
std::vector< Capnp_word_array_ptr > m_capnp_segments
After deserialization(), capnp-targeted data structure which is essentially vector<> of each Blob::co...
kj::ArrayPtr< const ::capnp::word > Capnp_word_array_ptr
Alias to capnp type that's similar to boost::asio::const_buffer but stores word* and word count inste...
@ S_DESERIALIZE_FAILED_INSUFFICIENT_SEGMENTS
Structured message deserialization: Tried to deserialize without enough input segments (e....
@ S_DESERIALIZE_FAILED_SEGMENT_MISALIGNED
Structured message deserialization: An input segment is not aligned as required.
Reader< ipc::shm::classic::Pool_arena > Reader
Convenience alias: transport::struc::shm::Reader that works with boost.ipc.shm pools from ipc::shm::c...
Definition: classic_fwd.hpp:39
Sub-module of Flow-IPC module ipc::transport providing transmission of structured messages specifical...
Definition: channel.cpp:31
std::vector< flow::util::Blob * > Segment_ptrs
Sequence of 1+ Blob pointers to blobs which must stay alive while these pointers may be dereferenced,...
Definition: struc_fwd.hpp:122
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:297
Implements Struct_builder::Config sub-concept.
flow::log::Logger * m_logger_ptr
Logger to use for logging subsequently.
Implements Struct_reader::Config sub-concept.
flow::log::Logger * m_logger_ptr
Logger to use for logging subsequently.
size_t m_n_segments_est
Best guess for how many times you expect to call add_serialization_segment(); or 0 if you have no gue...
Value for Struct_builder::Session when no extra information is needed when serializing Struct_builder...