VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
proxy_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 proxy_data.h
26 * @brief Zero-copy proxy message envelope carrying raw payload plus routing metadata.
27 *
28 * @details
29 * @c ProxyData is used by the VLink proxy layer to bundle a serialised message
30 * with its routing context (URL, serialisation type, source hostname) and
31 * control fields (control ID, mode, timestamp, sequence number) into a single
32 * flat allocation.
33 *
34 * The struct is exactly 80 bytes on 64-bit platforms. Internally a single
35 * owned buffer is laid out as:
36 *
37 * @code
38 * [ raw data | url string | ser type string | hostname string ]
39 * @endcode
40 *
41 * Position and length of each region are stored as @c uint32_t fields in the
42 * struct itself so that after binary round-trip the sub-buffers can be accessed
43 * as @c std::string_view without additional allocation.
44 *
45 * @par Binary wire format
46 * @code
47 * [ magic_begin (4) | ProxyData struct (80) | variable payload | magic_end (4) ]
48 * @endcode
49 *
50 * @par Usage
51 * @code
52 * vlink::zerocopy::ProxyData pd;
53 * pd.set_control_id(42);
54 * pd.set_timestamp(get_time_us());
55 * pd.create(raw_bytes, "dds://my/topic", "demo.proto.PointCloud",
56 * static_cast<uint32_t>(SchemaType::kProtobuf), "host01");
57 *
58 * vlink::Bytes wire;
59 * pd >> wire; // serialise
60 *
61 * vlink::zerocopy::ProxyData pd2;
62 * pd2 << wire; // deserialise (zero-copy, borrows wire)
63 * auto url = pd2.url(); // std::string_view into wire
64 * @endcode
65 *
66 * @note
67 * - 32-bit architectures emit a compile-time warning and are not supported.
68 * - After @c operator<<, all sub-buffer string_views reference memory inside
69 * the source @c Bytes. The @c Bytes must outlive the @c ProxyData.
70 * - @c is_valid() performs an additional internal consistency check that all
71 * position + size values are contiguous and sum correctly.
72 */
73
74#pragma once
75
76#include <cstdint>
77#include <string_view>
78
79#include "../base/bytes.h"
80
81namespace vlink {
82
83namespace zerocopy {
84
85/**
86 * @struct ProxyData
87 * @brief Proxy routing envelope: raw payload bundled with URL, serialisation type, and hostname.
88 *
89 * @details
90 * Used internally by the VLink proxy subsystem. The struct is 80 bytes on
91 * 64-bit targets. The variable-length tail buffer is allocated once by
92 * @c create() and is contiguous:
93 * @c [raw | url | ser | hostname].
94 */
95struct VLINK_EXPORT_AND_ALIGNED(8) ProxyData final {
96 /**
97 * @brief Default constructor.
98 *
99 * @details
100 * Verifies via @c static_assert that the struct is exactly 80 bytes on
101 * 64-bit platforms.
102 */
103 ProxyData() noexcept;
104
105 /**
106 * @brief Destructor -- frees the owned tail buffer if @c is_owner() is @c true.
107 */
108 ~ProxyData() noexcept;
109
110 /**
111 * @brief Copy constructor -- deep-copies @p target.
112 *
113 * @param target Source to copy.
114 */
115 ProxyData(const ProxyData& target) noexcept;
116
117 /**
118 * @brief Move constructor -- transfers ownership from @p target.
119 *
120 * @details
121 * After the call @p target is empty and does not own any buffer.
122 *
123 * @param target Source to move from.
124 */
125 ProxyData(ProxyData&& target) noexcept;
126
127 /**
128 * @brief Copy-assignment operator.
129 *
130 * @param target Source to copy. Self-assignment is a no-op.
131 * @return Reference to @c *this.
132 */
133 ProxyData& operator=(const ProxyData& target) noexcept;
134
135 /**
136 * @brief Move-assignment operator.
137 *
138 * @param target Source to move. Self-assignment is a no-op.
139 * @return Reference to @c *this.
140 */
141 ProxyData& operator=(ProxyData&& target) noexcept;
142
143 /**
144 * @brief Deserialises a @c ProxyData from a @c Bytes wire buffer.
145 *
146 * @details
147 * Validates magic-number sentinels and the internal region layout
148 * (positions and sizes must be contiguous and sum to @c size_).
149 * The tail buffer pointer references memory inside @p bytes (zero-copy);
150 * @p bytes must outlive this @c ProxyData.
151 *
152 * @param bytes Buffer produced by @c operator>>.
153 * @return @c true on success; @c false on magic-number mismatch,
154 * size inconsistency, or invalid region layout.
155 */
156 bool operator<<(const Bytes& bytes) noexcept;
157
158 /**
159 * @brief Serialises this @c ProxyData into a @c Bytes wire buffer.
160 *
161 * @details
162 * Writes the magic-number envelope, the struct fields, and the tail
163 * payload into @p bytes, resizing it as needed.
164 *
165 * @param bytes Output buffer (reallocated automatically if necessary).
166 * @return Always @c true.
167 */
168 bool operator>>(Bytes& bytes) const noexcept;
169
170 /**
171 * @brief Returns the proxy control identifier.
172 *
173 * @return Value set by @c set_control_id().
174 */
175 [[nodiscard]] uint32_t control_id() const noexcept;
176
177 /**
178 * @brief Returns the proxy operation mode.
179 *
180 * @return Value set by @c set_mode().
181 */
182 [[nodiscard]] uint32_t mode() const noexcept;
183
184 /**
185 * @brief Returns the message timestamp in microseconds.
186 *
187 * @return Value set by @c set_timestamp().
188 */
189 [[nodiscard]] int64_t timestamp() const noexcept;
190
191 /**
192 * @brief Returns the message sequence number.
193 *
194 * @return Value set by @c set_seq().
195 */
196 [[nodiscard]] int64_t seq() const noexcept;
197
198 /**
199 * @brief Returns the coarse schema family carried with this payload.
200 *
201 * @return Numeric @c SchemaType value stored by @c set_schema().
202 */
203 [[nodiscard]] uint32_t schema() const noexcept;
204
205 /**
206 * @brief Returns a shallow @c Bytes view of the raw message payload.
207 *
208 * @details
209 * The returned @c Bytes points into the internal tail buffer without
210 * copying. It must not outlive this @c ProxyData.
211 *
212 * @return Shallow @c Bytes of the raw payload, or empty if not set.
213 */
214 [[nodiscard]] Bytes raw() const noexcept;
215
216 /**
217 * @brief Returns the topic URL as a @c string_view.
218 *
219 * @details
220 * Points into the internal tail buffer. Lifetime is tied to this object.
221 *
222 * @return View of the URL string, or empty if not set.
223 */
224 [[nodiscard]] std::string_view url() const noexcept;
225
226 /**
227 * @brief Returns the serialisation type string as a @c string_view.
228 *
229 * @details
230 * For example @c "demo.proto.PointCloud" or @c "demo.fbs.CameraFrame".
231 * Points into the internal tail buffer.
232 *
233 * @return View of the serialisation type string, or empty if not set.
234 */
235 [[nodiscard]] std::string_view ser() const noexcept;
236
237 /**
238 * @brief Returns the source hostname as a @c string_view.
239 *
240 * @details
241 * Optional field; empty if not provided to @c create().
242 * Points into the internal tail buffer.
243 *
244 * @return View of the hostname string, or empty if not set.
245 */
246 [[nodiscard]] std::string_view hostname() const noexcept;
247
248 /**
249 * @brief Sets the proxy control identifier.
250 *
251 * @param control_id Control identifier value.
252 */
253 void set_control_id(uint32_t control_id) noexcept;
254
255 /**
256 * @brief Sets the proxy operation mode.
257 *
258 * @param mode Mode value.
259 */
260 void set_mode(uint32_t mode) noexcept;
261
262 /**
263 * @brief Sets the message timestamp in microseconds.
264 *
265 * @param timestamp Timestamp value (microseconds since epoch).
266 */
267 void set_timestamp(int64_t timestamp) noexcept;
268
269 /**
270 * @brief Sets the message sequence number.
271 *
272 * @param seq Sequence number.
273 */
274 void set_seq(int64_t seq) noexcept;
275
276 /**
277 * @brief Sets the coarse schema family associated with the payload.
278 *
279 * @param schema Numeric @c SchemaType value.
280 */
281 void set_schema(uint32_t schema) noexcept;
282
283 /**
284 * @brief Checks whether @p bytes contains a valid @c ProxyData wire buffer.
285 *
286 * @details
287 * Verifies minimum buffer size and both magic-number sentinels.
288 *
289 * @param bytes Buffer to validate.
290 * @return @c true if magic numbers match and size is sufficient.
291 */
292 [[nodiscard]] static bool check_valid(const Bytes& bytes) noexcept;
293
294 /**
295 * @brief Returns the total serialised byte count for this @c ProxyData.
296 *
297 * @details
298 * Equals: @c sizeof(magic_begin) + @c sizeof(ProxyData) + @c size() + @c sizeof(magic_end)
299 *
300 * @return Total bytes written by @c operator>>.
301 */
302 [[nodiscard]] size_t get_serialized_size() const noexcept;
303
304 /**
305 * @brief Returns @c true when all internal region positions and sizes are consistent.
306 *
307 * @details
308 * Checks that raw, url, ser, and hostname regions are contiguous and that
309 * their combined size equals the tail buffer size. Also requires a non-null
310 * data pointer and non-zero total size.
311 *
312 * @return @c true when the object holds valid, usable data.
313 */
314 [[nodiscard]] bool is_valid() const noexcept;
315
316 /**
317 * @brief Borrows the tail buffer from @p target without copying.
318 *
319 * @details
320 * Sets metadata and pointer to match @p target; @c is_owner() becomes
321 * @c false. Any previously owned buffer is freed.
322 *
323 * @param target Source to borrow from.
324 * @return @c false if @p target == @c *this, otherwise @c true.
325 */
326 bool shallow_copy(const ProxyData& target) noexcept;
327
328 /**
329 * @brief Deep-copies the tail buffer from @p target.
330 *
331 * @details
332 * Allocates a new buffer of the same size and copies the payload. If
333 * @c *this already owns a same-size buffer the data is copied in-place.
334 *
335 * @param target Source to copy.
336 * @return @c false if @p target == @c *this, otherwise @c true.
337 */
338 bool deep_copy(const ProxyData& target) noexcept;
339
340 /**
341 * @brief Transfers ownership from @p target to @c *this.
342 *
343 * @details
344 * After the call @p target is empty.
345 *
346 * @param target Source to move from.
347 * @return @c false if @p target == @c *this, otherwise @c true.
348 */
349 bool move_copy(ProxyData& target) noexcept;
350
351 /**
352 * @brief Constructs the envelope by packing all fields into a single allocation.
353 *
354 * @details
355 * Allocates a buffer of size @c raw.size() + url.size() + ser.size() + hostname.size()
356 * and copies each region in order. Any previously owned buffer is freed first.
357 *
358 * @param raw Raw serialised message payload.
359 * @param url Topic URL string (e.g., @c "dds://my/topic").
360 * @param ser Serialisation type (e.g., @c "demo.proto.PointCloud").
361 * @param schema Coarse schema family, typically a @c SchemaType value.
362 * @param hostname Optional source hostname; empty if not provided.
363 */
364 void create(const Bytes& raw, std::string_view url, std::string_view ser, uint32_t schema = 0,
365 std::string_view hostname = {}) noexcept;
366
367 /**
368 * @brief Releases all resources and resets all fields to zero.
369 */
370 void clear() noexcept;
371
372 /**
373 * @brief Returns the total tail buffer size in bytes.
374 *
375 * @details
376 * Equals the sum of the raw payload, URL, serialisation type, and hostname
377 * sizes.
378 *
379 * @return Total variable-length buffer size, or 0 if empty.
380 */
381 [[nodiscard]] size_t size() const noexcept;
382
383 /**
384 * @brief Returns @c true if this object owns its tail buffer.
385 *
386 * @details
387 * Owned buffers are freed in the destructor. Borrowed buffers (from
388 * @c shallow_copy or @c operator<<) are not freed.
389 *
390 * @return @c true when memory ownership is held.
391 */
392 [[nodiscard]] bool is_owner() const noexcept;
393
394 static constexpr bool kZerocopyTypes{true}; /// Internal
395
396 private:
397 uint8_t* data_{nullptr};
398 size_t size_{0};
399 uint32_t control_id_{0};
400 uint32_t mode_{0};
401 int64_t timestamp_{0};
402 int64_t seq_{0};
403 uint32_t data_pos_{0};
404 uint32_t data_size_{0};
405 uint32_t url_pos_{0};
406 uint32_t url_size_{0};
407 uint32_t ser_pos_{0};
408 uint32_t ser_size_{0};
409 uint32_t hostname_pos_{0};
410 uint32_t hostname_size_{0};
411 uint32_t schema_{0};
412 bool is_owner_{false};
413
414 static constexpr uint32_t kMagicNumberBegin{0x98B7F12A};
415 static constexpr uint32_t kMagicNumberEnd{0x98B7F12F};
416};
417
418} // namespace zerocopy
419
420} // namespace vlink
Versatile byte buffer with small-buffer optimisation, ownership semantics and compression.
#define VLINK_EXPORT_AND_ALIGNED(align_num)
Marks a class or variable as both exported and aligned to the given byte boundary.
定义 macros.h:103
Proxy routing envelope: raw payload bundled with URL, serialisation type, and hostname.