VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
dynamic_data.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 dynamic_data.h
26 * @brief Type-erased data container for runtime serialisation and deserialisation.
27 *
28 * @details
29 * @c DynamicData stores a serialized payload (@c Bytes) together with a type-name tag
30 * (up to @c kOffset = 20 bytes) embedded in the leading bytes of the buffer. This allows
31 * the payload to be transported through channels that do not know the compile-time message
32 * type, and later deserialized back to the concrete type.
33 *
34 * @par Internal layout
35 * @code
36 * [ type name (20 bytes max) | serialized payload ]
37 * ^--- type_ ^--- data_.data()
38 * @endcode
39 *
40 * The type name is stored in-place in the first @c kOffset bytes of the @c Bytes buffer
41 * and exposed as a @c std::string_view pointing into that buffer.
42 *
43 * @par Restrictions
44 * - Cannot serialize or deserialize another @c DynamicData object (static_assert).
45 * - Cannot serialize CDR types (static_assert).
46 * - The type name string literal (including NUL) must be shorter than @c kOffset (20) bytes (static_assert).
47 *
48 * @par Serialisation
49 * @code
50 * vlink::DynamicData dd;
51 * MyProtoMsg msg;
52 * msg.set_value(42);
53 * dd.load("MyProtoMsg", msg);
54 *
55 * // Store/transport dd ...
56 *
57 * MyProtoMsg recovered = dd.as<MyProtoMsg>();
58 * @endcode
59 *
60 * @par Binary transport (operator<< / operator>>)
61 * @code
62 * vlink::Bytes wire_bytes;
63 * dd >> wire_bytes; // serialize DynamicData to Bytes
64 *
65 * vlink::DynamicData dd2;
66 * dd2 << wire_bytes; // deserialize Bytes back to DynamicData
67 * @endcode
68 */
69
70#pragma once
71
72#include <memory>
73#include <string_view>
74
75#include "../serializer.h"
76
77namespace vlink {
78
79/**
80 * @class DynamicData
81 * @brief Runtime-typed container that serializes any VLink-compatible message type.
82 *
83 * @details
84 * Uses @c Serializer to pack the message into internal @c Bytes storage.
85 * The type tag is embedded in the first @c kOffset bytes of the buffer.
86 */
88 public:
89 /**
90 * @brief Constructs an empty @c DynamicData with no payload.
91 */
93
94 /**
95 * @brief Serializes @p t with a type-name tag into the internal buffer.
96 *
97 * @details
98 * The type name is stored in the first @c kOffset bytes of the underlying @c Bytes buffer.
99 * A @c static_assert enforces that @p SizeT < @c kOffset (20).
100 *
101 * @tparam SizeT Length of the type-name string literal including NUL.
102 * @tparam T Message type to serialize (must be supported by @c Serializer).
103 * @param type Type name string literal, e.g., @c "MyProtoMsg".
104 * @param t Message instance to serialize.
105 * @return Reference to @c *this for chaining.
106 *
107 * @note Logs a failure if serialisation returns @c false.
108 */
109 template <uint8_t SizeT, typename T>
110 DynamicData& load(const char (&type)[SizeT], const T& t);
111
112 /**
113 * @brief Deserializes the internal buffer into @p t.
114 *
115 * @details
116 * Uses @c Serializer to populate @p t from the payload bytes.
117 * Returns @c false if the buffer is empty or deserialisation fails.
118 *
119 * @tparam T Message type to deserialize into.
120 * @param t Output parameter populated on success.
121 * @return @c true if deserialization succeeded; @c false otherwise.
122 */
123 template <typename T>
124 bool convert(T& t) const;
125
126 /**
127 * @brief Deserializes the internal buffer and returns the result by value.
128 *
129 * @details
130 * Constructs a default @p T (or @c shared_ptr<T> for pointer types) and
131 * calls @c convert(). Returns a default-constructed @p T on failure.
132 *
133 * @tparam T Message type to deserialize.
134 * @return Deserialized instance, or default-constructed value on failure.
135 */
136 template <typename T>
137 [[nodiscard]] T as() const;
138
139 /**
140 * @brief Returns a const reference to the raw serialized bytes (including type tag).
141 *
142 * @return Internal @c Bytes buffer.
143 */
144 [[nodiscard]] const Bytes& get_data() const;
145
146 /**
147 * @brief Returns the type name string embedded in the buffer.
148 *
149 * @details
150 * Points into the first @c kOffset bytes of the internal @c Bytes buffer.
151 * The view is only valid for the lifetime of this @c DynamicData instance.
152 *
153 * @return @c string_view of the type name.
154 */
155 [[nodiscard]] const std::string_view& get_type() const;
156
157 /**
158 * @brief Returns @c true if no payload has been loaded.
159 *
160 * @return @c true if the internal @c Bytes buffer is empty.
161 */
162 [[nodiscard]] bool is_empty() const;
163
164 /**
165 * @brief Returns @c true if both @c DynamicData objects have identical buffers.
166 *
167 * @param target Right-hand side.
168 * @return @c true if the raw bytes are equal.
169 */
170 [[nodiscard]] bool operator==(const DynamicData& target) const;
171
172 /**
173 * @brief Returns @c true if the objects differ.
174 *
175 * @param target Right-hand side.
176 * @return @c true if the raw bytes differ.
177 */
178 [[nodiscard]] bool operator!=(const DynamicData& target) const;
179
180 /**
181 * @brief Compile-time trait marker -- returns @c true to identify this as a @c DynamicData type.
182 *
183 * @details
184 * Used internally by @c Serializer via template specialisation detection.
185 *
186 * @return Always @c true.
187 */
188 [[nodiscard]] static constexpr bool is_vlink_dynamic_data();
189
190 /**
191 * @brief Returns the byte offset where the serialized payload begins.
192 *
193 * @details
194 * Equal to @c kOffset (20). The first @c kOffset bytes are reserved for the type name.
195 *
196 * @return Offset value (20).
197 */
198 [[nodiscard]] static constexpr uint8_t get_offset();
199
200 /**
201 * @brief Deserializes a wire-format @c Bytes blob into this @c DynamicData.
202 *
203 * @param bytes Wire-format bytes produced by @c operator>>.
204 * @return @c true on success; @c false if parsing failed.
205 */
206 bool operator<<(const Bytes& bytes) noexcept;
207
208 /**
209 * @brief Serializes this @c DynamicData to a wire-format @c Bytes blob.
210 *
211 * @param bytes Output buffer.
212 * @return @c true on success; @c false if the internal buffer is empty.
213 */
214 bool operator>>(Bytes& bytes) const noexcept;
215
216 private:
217 static constexpr uint8_t kOffset{20};
218 Bytes data_;
219 std::string_view type_;
220};
221
222////////////////////////////////////////////////////////////////
223/// Details
224////////////////////////////////////////////////////////////////
225
226template <uint8_t SizeT, typename T>
227inline DynamicData& DynamicData::load(const char (&type)[SizeT], const T& t) {
228 static_assert(SizeT < get_offset(), "DynamicData name out of size.");
229 static_assert(!std::is_same_v<DynamicData, T>, "DynamicData can not serialize self.");
230 static_assert(!Serializer::is_cdr_type<T>(), "DynamicData can not serialize cdr data.");
231
233
234 if VUNLIKELY (!ret) {
235 VLOG_F("DynamicData serialize failed.");
236 }
237
238 if constexpr (SizeT > 0) {
239 std::memcpy(data_.real_data(), type, SizeT);
240 type_ = std::string_view(reinterpret_cast<const char*>(data_.real_data()), SizeT);
241 } else {
242 type_ = std::string_view();
243 }
244
245 return *this;
246}
247
248template <typename T>
249inline bool DynamicData::convert(T& t) const {
250 static_assert(!std::is_same_v<DynamicData, T>, "DynamicData can not deserialize self.");
251 static_assert(!Serializer::is_cdr_type<T>(), "DynamicData can not deserialize cdr data.");
252
253 if VUNLIKELY (data_.empty()) {
254 return false;
255 }
256
258}
259
260template <typename T>
261inline T DynamicData::as() const {
262 T t;
263
264 if constexpr (Traits::IsSharedPtr<T>()) {
265 t = std::make_shared<typename T::element_type>();
266 }
267
268 if VUNLIKELY (!convert(t)) {
269 VLOG_F("DynamicData deserialize failed.");
270 return T{};
271 }
272
273 return t;
274}
275
276inline constexpr bool DynamicData::is_vlink_dynamic_data() { return true; }
277
278inline constexpr uint8_t DynamicData::get_offset() { return kOffset; }
279
280} // namespace vlink
#define VLOG_F(...)
定义 logger.h:856
#define VUNLIKELY(...)
Shorthand alias for VLINK_UNLIKELY. Hints that the expression is unlikely true.
定义 macros.h:302
#define VLINK_EXPORT
定义 macros.h:85
Compile-time type-detection and serialisation utilities for VLink messages.