VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
serializer.h
浏览该文件的文档.
1/*
2 * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 * Author: Thun Lu <thun.lu@zohomail.cn>
4 * Repo: https://github.com/thun-res/vlink
5 * _ __ __ _ __
6 * | | / / / / (_) ____ / /__
7 * | | / / / / / / / __ \ / //_/
8 * | |/ / / /___ / / / / / / / ,<
9 * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24/**
25 * @file serializer.h
26 * @brief Compile-time type-detection and serialisation utilities for VLink messages.
27 *
28 * @details
29 * The @c Serializer namespace provides a unified serialisation and
30 * deserialisation interface that automatically selects the correct codec
31 * based on the C++ type of the message via @c constexpr if chains.
32 *
33 * @par Supported Serializer Types
34 * | Type constant | C++ Type Criteria | Notes |
35 * | ------------------- | ------------------------------------------------------ | --------------------------------- |
36 * | @c kBytesType | @c T == Bytes | Pass-through, no-copy. |
37 * | @c kDynamicType | Has @c is_vlink_dynamic_data() member | Dynamic type via @c operator>>/<< |
38 * | @c kCdrType | Has @c serialize(Cdr&) and @c deserialize(Cdr&) | FastDDS CDR codec. |
39 * | @c kProtoType | Has @c SerializeToArray() and @c ParseFromArray() | Protobuf by value. |
40 * | @c kProtoPtrType | Pointer with @c SerializeToArray / @c ParseFromArray | Arena-managed proto pointer. |
41 * | @c kFlatTableType | Inherits @c flatbuffers::NativeTable | FlatBuffers native table. |
42 * | @c kFlatPtrType | Pointer to @c flatbuffers::Table subclass | Zero-copy FlatBuffers read. |
43 * | @c kFlatBuilderType | Has @c fbb_ member and @c Finish() | FlatBuffers builder. |
44 * | @c kCustomType | Has @c operator>>(Bytes&) and @c operator<<(const Bytes&) | User-defined codec. |
45 * | @c kStringType | @c T == std::string | UTF-8 string. |
46 * | @c kCharsType | Constructible as @c std::string but not @c std::string | C string literal / @c char*. |
47 * | @c kStreamType | Has @c operator<< and @c operator>> with stringstream | Stream-based text encoding. |
48 * | @c kStandardType | Trivial standard-layout value (POD) | Byte-copied directly. |
49 * | @c kStandardPtrType | Pointer to trivial standard-layout type | Zero-copy POD pointer. |
50 *
51 * @par Type Detection
52 * @code
53 * // At compile time, get the Type enumerator for any message type:
54 * constexpr auto t = Serializer::get_type_of<MyMsg>(); // e.g. kProtoType
55 * static_assert(Serializer::is_supported(t), "");
56 * @endcode
57 *
58 * @par Serialize and Deserialize
59 * @code
60 * MyProto msg;
61 * Bytes bytes;
62 * Serializer::serialize(msg, bytes); // MyProto -> Bytes
63 *
64 * MyProto out;
65 * Serializer::deserialize(bytes, out); // Bytes -> MyProto
66 * @endcode
67 *
68 * @par Custom Type
69 * Implement @c operator>> and @c operator<< on your type:
70 * @code
71 * struct MyCustomMsg {
72 * int x;
73 * void operator>>(vlink::Bytes& out) const { ... } // serialize
74 * void operator<<(const vlink::Bytes& in) { ... } // deserialize
75 * };
76 * // Now Serializer::get_type_of<MyCustomMsg>() == kCustomType
77 * @endcode
78 *
79 * @par Transport-aware Serialization
80 * Some transports (e.g. @c dds://) use a special fast-path for CDR types
81 * (pointer passing instead of byte-copy). Pass the @c TransportType to the
82 * explicit overloads to activate the transport-specific path:
83 * @code
84 * Serializer::serialize<kCdrType>(msg, bytes, TransportType::kDds);
85 * @endcode
86 *
87 * @note All functions in this namespace are @c static and @c inline.
88 * The namespace name starts with a capital letter by convention (matches
89 * VLink style). Direct use by application code is rarely needed; the
90 * framework calls these functions automatically inside @c publish(),
91 * @c listen(), @c invoke(), etc.
92 */
93
94#pragma once
95
96#include <string>
97
98#include "./base/bytes.h"
99#include "./impl/types.h"
100
101namespace vlink {
102
103/**
104 * @namespace Serializer
105 * @brief Compile-time type detection and codec dispatch for VLink messages.
106 *
107 * @details
108 * All functions are @c static @c inline template functions. Application code
109 * rarely calls these directly; the framework invokes them inside
110 * @c publish(), @c listen(), @c invoke(), @c set(), and @c get().
111 */
112namespace Serializer { // NOLINT(readability-identifier-naming)
113
114/**
115 * @enum Type
116 * @brief Identifies the serialisation codec to use for a given C++ type.
117 *
118 * @details
119 * Resolved at compile time by @c get_type_of<T>(). The value is stored
120 * in the @c Publisher / @c Subscriber etc. as a @c constexpr member so that
121 * all codec dispatch is zero-cost at runtime.
122 */
123enum Type : uint8_t {
124 kUnknownType = 0, ///< Unsupported type -- @c is_supported() returns @c false.
125 kBytesType = 1, ///< @c Bytes -- raw byte pass-through.
126 kDynamicType = 2, ///< Dynamic typed data via @c is_vlink_dynamic_data().
127 kCustomType = 3, ///< User-defined via @c operator>>(Bytes&) / @c operator<<(const Bytes&).
128 kCdrType = 4, ///< FastDDS CDR via @c serialize(Cdr&) / @c deserialize(Cdr&).
129 kProtoType = 5, ///< Protobuf value (@c MessageLite derived).
130 kProtoPtrType = 6, ///< Protobuf raw pointer (Arena-managed).
131 kFlatTableType = 7, ///< FlatBuffers NativeTable (object API).
132 kFlatPtrType = 8, ///< Pointer to @c flatbuffers::Table (zero-copy read).
133 kFlatBuilderType = 9, ///< FlatBuffers builder (@c fbb_ + @c Finish()).
134 kStringType = 10, ///< @c std::string -- UTF-8 text.
135 kCharsType = 11, ///< @c char* / string literal.
136 kStreamType = 12, ///< Stream-serialisable via @c operator<<(std::stringstream).
137 kStandardType = 13, ///< Trivial standard-layout struct (POD value).
138 kStandardPtrType = 14, ///< Pointer to trivial standard-layout struct (POD pointer).
139};
140
141/**
142 * @brief Returns @c true when @p type identifies a supported serializer.
143 *
144 * @details
145 * @c kUnknownType is the only unsupported value. This function is called
146 * by the @c static_assert in every node constructor to catch unsupported
147 * message types at compile time.
148 *
149 * @param type Serializer type enumerator.
150 * @return @c false only for @c kUnknownType.
151 */
152[[maybe_unused]] [[nodiscard]] static constexpr bool is_supported(Type type) noexcept;
153
154/**
155 * @brief Deduces the @c Type enumerator for @c T at compile time.
156 *
157 * @details
158 * Evaluates a compile-time @c if constexpr chain that tests each codec's
159 * trait (e.g. @c is_proto_type<T>()) and returns the first matching @c Type.
160 * Returns @c kUnknownType if no codec matches.
161 *
162 * The detection order is:
163 * Bytes, Dynamic, CDR, Proto, ProtoPtr, FlatTable, FlatPtr, FlatBuilder,
164 * Custom, String, Chars, Standard, StandardPtr, Stream.
165 *
166 * @tparam T The C++ message type to classify.
167 * @return @c Type enumerator identifying the codec for @c T.
168 */
169template <typename T>
170[[nodiscard]] static constexpr Type get_type_of() noexcept;
171
172/**
173 * @brief Returns the coarse schema family for @p T with an explicit codec tag.
174 *
175 * @tparam TypeT Explicit VLink codec kind.
176 * @tparam T C++ message type to classify.
177 * @return @c SchemaType::kProtobuf, @c SchemaType::kFlatbuffers,
178 * @c SchemaType::kZeroCopy, or @c SchemaType::kRaw for
179 * schema-less payload families.
180 */
181template <Type TypeT, typename T>
182[[nodiscard]] static constexpr SchemaType get_schema_type() noexcept;
183
184/**
185 * @brief Returns the coarse schema family inferred from @p T.
186 *
187 * @tparam T C++ message type to classify.
188 * @return @c SchemaType::kProtobuf, @c SchemaType::kFlatbuffers,
189 * @c SchemaType::kZeroCopy, or @c SchemaType::kRaw when the
190 * payload is schema-less but still has a stable family.
191 */
192template <typename T>
193[[nodiscard]] static constexpr SchemaType get_schema_type() noexcept;
194
195/**
196 * @brief Returns the serialisation type name string for @c T with explicit @c TypeT.
197 *
198 * @details
199 * Returns a human-readable type identifier used by the framework for
200 * type-matching between publisher and subscriber (e.g. DDS topic type name,
201 * Protobuf fully-qualified name, FlatBuffers table name). Returns an empty
202 * string for types that have no meaningful type name (e.g. @c kBytesType).
203 *
204 * @tparam TypeT Explicit serializer type.
205 * @tparam T C++ message type.
206 * @return Type name string; empty if not applicable.
207 */
208template <Type TypeT, typename T>
209[[nodiscard]] static std::string get_serialized_type() noexcept;
210
211/**
212 * @brief Returns the serialisation type name string for @c T (type auto-detected).
213 *
214 * @tparam T C++ message type.
215 * @return Type name string; empty if not applicable.
216 */
217template <typename T>
218[[nodiscard]] static std::string get_serialized_type() noexcept;
219
220/**
221 * @brief Returns the exact serialised byte size for a given @p src value.
222 *
223 * @details
224 * Used to pre-allocate loaned buffers before serializing. Returns @c 0 for
225 * types whose serialized size is not known ahead of time (e.g. @c kBytesType,
226 * @c kStringType, @c kFlatTableType). For @c kStandardType returns
227 * @c sizeof(T).
228 *
229 * @tparam TypeT Serializer type.
230 * @tparam T C++ message type.
231 * @param src Source value to measure.
232 * @return Byte count needed to serialise @p src; @c 0 if unknown.
233 */
234template <Type TypeT, typename T>
235[[nodiscard]] static size_t get_serialized_size(const T& src) noexcept;
236
237/**
238 * @brief Returns the serialized byte size (type auto-detected).
239 *
240 * @tparam T C++ message type.
241 * @param src Source value to measure.
242 * @return Byte count; @c 0 if unknown.
243 */
244template <typename T>
245[[nodiscard]] static size_t get_serialized_size(const T& src) noexcept;
246
247/**
248 * @brief Serializes @p src into @p des with explicit type and transport hints.
249 *
250 * @details
251 * The @p transport parameter activates transport-specific fast paths (e.g. CDR
252 * pointer passing for @c kDds). Pass @c TransportType::kUnknown for the default
253 * copy-based path. The @p offset parameter prepends @p offset zero bytes
254 * before the payload (used internally for some transports).
255 *
256 * @tparam TypeT Serializer type.
257 * @tparam T C++ message type.
258 * @param src Source value to serialise.
259 * @param des Destination @c Bytes buffer (may be pre-allocated or loaned).
260 * @param transport Active transport backend for fast-path selection.
261 * @param offset Number of header bytes to prepend (default @c 0).
262 * @return @c true on success; @c false on serialisation failure.
263 */
264template <Type TypeT, typename T>
265static bool serialize(const T& src, Bytes& des, TransportType transport = TransportType::kUnknown, uint8_t offset = 0);
266
267/**
268 * @brief Serializes @p src into @p des (type and transport auto-detected).
269 *
270 * @tparam T C++ message type.
271 * @param src Source value.
272 * @param des Destination @c Bytes.
273 * @return @c true on success.
274 */
275template <typename T>
276static bool serialize(const T& src, Bytes& des);
277
278/**
279 * @brief Deserializes @p src bytes into @p des with explicit type and transport hints.
280 *
281 * @details
282 * The @p transport activates transport-specific fast paths (e.g. @c kDds
283 * dereferences a CDR pointer stored in @p src instead of copying bytes).
284 *
285 * @tparam TypeT Serializer type.
286 * @tparam T C++ message type.
287 * @param src Source @c Bytes buffer.
288 * @param des Destination value to fill.
289 * @param transport Active transport backend.
290 * @return @c true on success; @c false on parse failure.
291 */
292template <Type TypeT, typename T>
293static bool deserialize(const Bytes& src, T& des, TransportType transport = TransportType::kUnknown);
294
295/**
296 * @brief Deserializes @p src bytes into @p des (type and transport auto-detected).
297 *
298 * @tparam T C++ message type.
299 * @param src Source @c Bytes buffer.
300 * @param des Destination value.
301 * @return @c true on success.
302 */
303template <typename T>
304static bool deserialize(const Bytes& src, T& des);
305
306/**
307 * @brief Converts between two types where at least one is @c Bytes.
308 *
309 * @details
310 * A compile-time @c static_assert enforces that @c SrcT or @c DesT (or both)
311 * is @c Bytes. The three cases are:
312 * - Both @c Bytes: shallow-copies @p src to @p des.
313 * - @c DesT == @c Bytes: calls @c serialize(src, des).
314 * - @c SrcT == @c Bytes: calls @c deserialize(src, des).
315 *
316 * @tparam SrcT Source type.
317 * @tparam DesT Destination type.
318 * @param src Source value.
319 * @param des Destination value.
320 * @return @c true on success.
321 */
322template <typename SrcT, typename DesT>
323static bool convert(const SrcT& src, DesT& des);
324
325/**
326 * @brief Dereferences a value, unwrapping @c shared_ptr if necessary.
327 *
328 * @details
329 * If @c T is a @c shared_ptr<U>, returns @c *t; otherwise returns @c t.
330 * Used internally so serialisation code handles both value and shared-ptr
331 * message types uniformly.
332 *
333 * @tparam T The input type (value or @c shared_ptr).
334 * @param t Input value.
335 * @return Reference to the underlying value.
336 */
337template <typename T>
338[[nodiscard]] static constexpr auto& deref(const T& t) noexcept;
339
340/**
341 * @brief Returns @c true if @c T is exactly @c Bytes.
342 *
343 * @tparam T Type to test.
344 * @return @c true for @c Bytes.
345 */
346template <typename T>
347[[nodiscard]] static constexpr bool is_bytes_type() noexcept;
348
349/**
350 * @brief Returns @c true if @c T is a VLink dynamic data type.
351 *
352 * @details
353 * Dynamic types have an @c is_vlink_dynamic_data() member.
354 *
355 * @tparam T Type to test.
356 * @return @c true for dynamic data types.
357 */
358template <typename T>
359[[nodiscard]] static constexpr bool is_dynamic_type() noexcept;
360
361/**
362 * @brief Returns @c true if @c T is a FastDDS CDR-serialisable type.
363 *
364 * @details
365 * Requires @c fastcdr to be present and the type to have both
366 * @c serialize(Cdr&) and @c deserialize(Cdr&) methods, or its name to
367 * contain the @c VLINK_FASTDDS_IDL_PREFIX prefix.
368 *
369 * @tparam T Type to test.
370 * @return @c true for CDR types when @c fastcdr is available.
371 */
372template <typename T>
373[[nodiscard]] static constexpr bool is_cdr_type() noexcept;
374
375/**
376 * @brief Returns @c true if @c T is a Protobuf message value type.
377 *
378 * @details
379 * Requires @c protobuf to be present and the type to have both
380 * @c SerializeToArray() and @c ParseFromArray() methods.
381 *
382 * @tparam T Type to test.
383 * @return @c true for Protobuf value types.
384 */
385template <typename T>
386[[nodiscard]] static constexpr bool is_proto_type() noexcept;
387
388/**
389 * @brief Returns @c true if @c T is a raw pointer to a Protobuf message.
390 *
391 * @tparam T Type to test (expected to be @c MyProto*).
392 * @return @c true for Protobuf pointer types.
393 */
394template <typename T>
395[[nodiscard]] static constexpr bool is_proto_ptr_type() noexcept;
396
397/**
398 * @brief Returns @c true if @c T is a FlatBuffers NativeTable type.
399 *
400 * @details
401 * Requires @c flatbuffers and the type (or its @c shared_ptr element)
402 * to be derived from @c flatbuffers::NativeTable.
403 *
404 * @tparam T Type to test.
405 * @return @c true for FlatBuffers NativeTable types.
406 */
407template <typename T>
408[[nodiscard]] static constexpr bool is_flat_table_type() noexcept;
409
410/**
411 * @brief Returns @c true if @c T is a FlatBuffers builder type.
412 *
413 * @details
414 * Requires @c flatbuffers and the type to have both a @c fbb_ member and
415 * a @c Finish() method.
416 *
417 * @tparam T Type to test.
418 * @return @c true for FlatBuffers builder types.
419 */
420template <typename T>
421[[nodiscard]] static constexpr bool is_flat_builder_type() noexcept;
422
423/**
424 * @brief Returns @c true if @c T is a raw pointer to a @c flatbuffers::Table.
425 *
426 * @tparam T Type to test (expected to be @c MyTable*).
427 * @return @c true for FlatBuffers Table pointer types.
428 */
429template <typename T>
430[[nodiscard]] static constexpr bool is_flat_ptr_type() noexcept;
431
432/**
433 * @brief Returns @c true if @c T provides custom @c operator>> / @c operator<<.
434 *
435 * @details
436 * Checks via @c Traits::Operatorable whether @c T supports @c operator>>(Bytes&)
437 * and @c operator<<(const Bytes&).
438 *
439 * @tparam T Type to test.
440 * @return @c true for custom-codec types.
441 */
442template <typename T>
443[[nodiscard]] static constexpr bool is_custom_type() noexcept;
444
445/**
446 * @brief Returns @c true if @c T is @c std::string.
447 *
448 * @tparam T Type to test.
449 * @return @c true only for @c std::string.
450 */
451template <typename T>
452[[nodiscard]] static constexpr bool is_string_type() noexcept;
453
454/**
455 * @brief Returns @c true if @c T is constructible from @c std::string (but is not @c std::string).
456 *
457 * @details
458 * Matches @c char*, @c const char*, and string literal types.
459 *
460 * @tparam T Type to test.
461 * @return @c true for C-string types.
462 */
463template <typename T>
464[[nodiscard]] static constexpr bool is_chars_type() noexcept;
465
466/**
467 * @brief Returns @c true if @c T supports both @c operator<< and @c operator>> with @c std::stringstream.
468 *
469 * @details
470 * Detected via @c Traits::Operatorable<std::stringstream, T>(), which requires
471 * both @c ss << t and @c ss >> t to be well-formed. Non-pointer types that
472 * support bidirectional streaming via @c std::stringstream (e.g. arithmetic
473 * types or types with custom stream operator overloads) match. Note that
474 * higher-priority codecs (e.g. Proto, CDR) are checked first in
475 * @c get_type_of(), so this function is only reached for types that do not
476 * match any earlier codec.
477 *
478 * @tparam T Type to test.
479 * @return @c true for stream-serialisable types.
480 */
481template <typename T>
482[[nodiscard]] static constexpr bool is_stream_type() noexcept;
483
484/**
485 * @brief Returns @c true if @c T is a trivial standard-layout value type (POD).
486 *
487 * @details
488 * Matches types where @c std::is_trivial_v and @c std::is_standard_layout_v
489 * are both @c true and the type is not a pointer. Such types are byte-copied
490 * directly into/from a @c Bytes buffer of exactly @c sizeof(T) bytes.
491 *
492 * @tparam T Type to test.
493 * @return @c true for POD value types.
494 */
495template <typename T>
496[[nodiscard]] static constexpr bool is_standard_type() noexcept;
497
498/**
499 * @brief Returns @c true if @c T is a pointer to a trivial standard-layout type.
500 *
501 * @details
502 * Matches @c T* where @c std::is_trivial_v<T> && @c std::is_standard_layout_v<T>.
503 * The pointer is reinterpreted (not dereferenced and copied) for zero-copy usage.
504 *
505 * @tparam T Pointer type to test.
506 * @return @c true for POD pointer types.
507 */
508template <typename T>
509[[nodiscard]] static constexpr bool is_standard_ptr_type() noexcept;
510
511} // namespace Serializer
512
513} // namespace vlink
514
515#include "./internal/serializer-inl.h"
Versatile byte buffer with small-buffer optimisation, ownership semantics and compression.
Compile-time type detection and codec dispatch for VLink messages.
STL namespace
Core type definitions shared across all VLink node implementations.