VLink  2.0.0
A high-performance communication middleware
intra_data.h
Go to the documentation of this file.
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 intra_data.h
26  * @brief Reference-counted in-process payload type used by the @c intra:// backend.
27  *
28  * @details
29  * This is an internal implementation header used by the public publisher and
30  * subscriber templates when they target the @c intra:// transport; it should not
31  * be included directly by application code. @c IntraData is the shared-ownership
32  * vehicle that lets a co-located publisher and subscriber exchange a message by
33  * pointer instead of going through a full serialise / deserialise round trip.
34  *
35  * @par In-process hand-off
36  * @code
37  * Publisher thread Subscriber thread
38  * ---------------- ------------------
39  * data = MyMsgIntra::create() shared_ptr -> queue
40  * data->value = ... ^
41  * pub.publish(data) ---------------------+
42  * v
43  * sub.listen()
44  * |
45  * v
46  * use data->value directly
47  * @endcode
48  *
49  * @par IntraDataType contract
50  * Concrete subtypes emitted by @c VLINK_INTRA_DATA_DECLARE add:
51  * - A typed @c value member carrying the user payload.
52  * - @c operator<< and @c operator>> for on-demand serialisation when the
53  * message has to be replicated across a non-intra boundary (e.g. recording).
54  * - @c get_serialized_size(), @c get_serialized_type() and @c get_schema_type()
55  * helpers shared with the public @c Serializer API.
56  *
57  * @par Example
58  * @code
59  * // 1. Declare the generated container pair next to the message type:
60  * VLINK_INTRA_DATA_DECLARE(MyProtoMsg, MyProtoIntra)
61  *
62  * // 2. Publish (zero-copy path):
63  * auto data = MyProtoIntra::create();
64  * data->value.set_field(42);
65  * pub.publish(data);
66  *
67  * // 3. Subscribe (zero-copy path):
68  * sub.listen([](const MyProtoIntra& intra) {
69  * process(intra->value);
70  * });
71  * @endcode
72  *
73  * @note Only the @c intra:// transport understands @c IntraData; calling
74  * @c write(IntraData) on any other publisher backend logs a warning and
75  * returns @c false.
76  */
77 
78 #pragma once
79 
80 #include <memory>
81 #include <string>
82 
83 #include "../serializer.h"
84 #include "./types.h"
85 
86 namespace vlink {
87 
88 /**
89  * @struct IntraDataType
90  * @brief Polymorphic base of every in-process payload container.
91  *
92  * @details
93  * Concrete subtypes are emitted by @c VLINK_INTRA_DATA_DECLARE. They store
94  * the actual message value and implement the serialisation operators that
95  * convert between the in-memory representation and a @c Bytes buffer when the
96  * message crosses a transport boundary.
97  */
98 struct IntraDataType {
99  IntraDataType() = default;
100  virtual ~IntraDataType() = default;
101 };
102 
103 /**
104  * @brief Shared-ownership handle for an @c IntraDataType payload.
105  *
106  * @details
107  * Publishers and subscribers exchange messages by copying this @c shared_ptr,
108  * avoiding any payload copy. Use the @c declare_name wrapper generated by
109  * @c VLINK_INTRA_DATA_DECLARE, or downcast manually with
110  * @c std::static_pointer_cast.
111  */
112 using IntraData = std::shared_ptr<IntraDataType>;
113 
114 } // namespace vlink
115 
116 /**
117  * @def VLINK_INTRA_DATA_DECLARE
118  * @brief Emits a typed in-process container pair around an arbitrary message type.
119  *
120  * @details
121  * Expansion produces:
122  *
123  * -# @c declare_name##Type -- a concrete @c IntraDataType subclass with:
124  * - @c target_type value member.
125  * - @c static constexpr kValueType matching @c Serializer::get_type_of<>.
126  * - @c operator<<(const Bytes&) deserialising into @c value.
127  * - @c operator>>(Bytes&) serialising from @c value.
128  * - @c get_serialized_size(), @c get_serialized_type() and
129  * @c get_schema_type() helpers consistent with the public serializer API.
130  * - A @c static_assert ensuring @c target_type is a supported serializer type.
131  *
132  * -# @c declare_name -- a @c std::shared_ptr<declare_name##Type> wrapper with
133  * constructors that accept the underlying @c shared_ptr and a static
134  * @c create() factory that allocates a fresh instance.
135  *
136  * The static @c get_serialized_type() returns an empty string for raw @c Bytes
137  * instantiations by design; this matches the contract documented in
138  * @c serializer.h.
139  *
140  * @param target_type User message type, must satisfy @c Serializer::is_supported.
141  * @param declare_name Identifier prefix for the generated container types.
142  */
143 #define VLINK_INTRA_DATA_DECLARE(target_type, declare_name) \
144  struct declare_name##Type : public vlink::IntraDataType { \
145  target_type value; \
146  \
147  static constexpr vlink::Serializer::Type kValueType = vlink::Serializer::get_type_of<target_type>(); \
148  \
149  static_assert(vlink::Serializer::is_supported(kValueType), \
150  "VLINK_INTRA_DATA_DECLARE(target_type) is not a supported Serializer type."); \
151  \
152  bool operator<<(const vlink::Bytes& bytes) noexcept { \
153  return vlink::Serializer::deserialize<kValueType>(bytes, value); \
154  } \
155  \
156  bool operator>>(vlink::Bytes& bytes) const noexcept { \
157  return vlink::Serializer::serialize<kValueType>(value, bytes); \
158  } \
159  \
160  [[nodiscard]] size_t get_serialized_size() const noexcept { \
161  return vlink::Serializer::get_serialized_size<kValueType>(value); \
162  } \
163  \
164  [[nodiscard]] static std::string get_serialized_type() noexcept { \
165  return vlink::Serializer::get_serialized_type<kValueType, target_type>(); \
166  } \
167  \
168  [[nodiscard]] static constexpr vlink::SchemaType get_schema_type() noexcept { \
169  return vlink::Serializer::get_schema_type<kValueType, target_type>(); \
170  } \
171  }; \
172  \
173  struct declare_name : public std::shared_ptr<declare_name##Type> { \
174  using Base = std::shared_ptr<declare_name##Type>; \
175  using Base::Base; \
176  \
177  /*NOLINTBEGIN*/ \
178  declare_name() noexcept = default; \
179  \
180  declare_name(Base&& other) noexcept : Base(std::move(other)) {} \
181  \
182  declare_name(const Base& other) noexcept : Base(other) {} \
183  \
184  [[nodiscard]] static declare_name create() noexcept { \
185  return declare_name(std::make_shared<declare_name##Type>()); \
186  } \
187  /*NOLINTEND*/ \
188  };
Core enumerations and small value types shared by the entire VLink implementation layer.