VLink  2.1.0
A high-performance communication middleware
conf.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 conf.h
26  * @brief Transport-configuration base contract and the supporting boilerplate macros.
27  *
28  * @details
29  * This is an internal implementation header used by the public node templates and
30  * by every transport-specific @c *Conf class; user code should never include it
31  * directly. The @c Conf base struct is the bridge between the URL parsing layer
32  * and the concrete factories that produce @c NodeImpl instances. A typical node
33  * construction follows the chain
34  * @c Url -> concrete @c Conf -> @c Conf::create_xxx() -> @c NodeImpl subclass.
35  *
36  * @par Inheritance hierarchy
37  * @code
38  * +--------+
39  * | Conf |
40  * +---+----+
41  * |
42  * +---------+--------+--------+---------+----------+--------------+-----------+
43  * | | | | | | | |
44  * IntraConf ShmConf Shm2Conf ZenohConf DdsConf DdscConf MqttConf ...etc
45  * (DdsrConf, SomeipConf, FdbusConf, plugin Conf)
46  * @endcode
47  *
48  * @par Virtual interface contract
49  * | Method | Default behaviour | Subclass responsibility |
50  * | ---------------------------- | --------------------------------------------- | ---------------------------------- |
51  * | @c parse(impl_type) | Caches @p impl_type; rejects @c kUnknown. | Validate transport-specific data. |
52  * | @c is_valid() | Returns @c false. | Report readiness for factories. |
53  * | @c get_impl_type() | Returns the cached value from @c parse(). | Usually inherited unchanged. |
54  * | @c get_transport_type() | Returns @c TransportType::kUnknown. | Return the backend identifier. |
55  * | @c parse_protocol(protocol) | Returns @c false. | Pull URL fields into the conf. |
56  * | @c create_publisher() / etc. | Returns @c nullptr. | Allocate the matching @c NodeImpl. |
57  *
58  * @par Macro reference
59  * | Macro | Purpose |
60  * | -------------------------------- | -------------------------------------------------------------------- |
61  * | @c VLINK_DECLARE_CONF_FRIEND | Grants friend access to all six public Node<> templates. |
62  * | @c VLINK_CONF_IMPL(classname) | Bundles friend grant + standard override declarations + ostream op. |
63  * | @c VLINK_ALLOW_IMPL_TYPE(type) | Records which @c ImplType bits a conf may serve, for compile checks. |
64  * | @c VLINK_DECLARE_GLOBAL_PROPERTY | Declares static thread-count and global-property storage in a conf. |
65  * | @c VLINK_DEFINE_GLOBAL_PROPERTY | Provides the storage definitions for the declaration above. |
66  *
67  * @par Example
68  * @code
69  * // include/myapp/my_conf.h
70  * struct MyConf final : public vlink::Conf {
71  * VLINK_CONF_IMPL(MyConf)
72  * VLINK_ALLOW_IMPL_TYPE(vlink::kPublisher | vlink::kSubscriber)
73  * VLINK_DECLARE_GLOBAL_PROPERTY()
74  *
75  * std::string host;
76  * uint16_t port{0};
77  * };
78  *
79  * // src/myapp/my_conf.cc
80  * VLINK_DEFINE_GLOBAL_PROPERTY(MyConf)
81  *
82  * void MyConf::global_init() { setup_shared_transport_state(); }
83  * bool MyConf::is_valid() const { return !host.empty() && port != 0; }
84  * @endcode
85  */
86 
87 #pragma once
88 
89 #include <map>
90 #include <memory>
91 #include <shared_mutex>
92 #include <string>
93 #include <utility>
94 
95 #include "../base/macros.h"
96 #include "./types.h"
97 
98 namespace vlink {
99 
100 /**
101  * @struct Conf
102  * @brief Abstract base for every transport-specific configuration aggregate.
103  *
104  * @details
105  * Holds the cached @c ImplType selected by @c parse() and declares the protected
106  * factory hooks that the public node templates use to instantiate @c NodeImpl
107  * peers. Default implementations of the factory hooks return @c nullptr so
108  * subclasses only need to override the roles they actually support; combine
109  * with @c VLINK_ALLOW_IMPL_TYPE to make the compile-time guard explicit.
110  *
111  * @note Instances are never owned by application code; they are produced by
112  * @c Url and live as long as the node that references them.
113  */
115  /**
116  * @brief Key/value property map shared between confs and node implementations.
117  *
118  * @details
119  * Stores transport tuning entries (e.g. @c "dds.ip" = @c "127.0.0.1") that
120  * are read by backends during @c init() and by helpers such as @c SslOptions.
121  */
122  using PropertiesMap = std::map<std::string, std::string>;
123 
124  /**
125  * @brief Virtual destructor.
126  */
127  virtual ~Conf();
128 
129  /**
130  * @brief Validates the conf for @p impl_type and caches it for subsequent factories.
131  *
132  * @details
133  * The base implementation rejects @c kUnknownImplType (the underlying logger
134  * call is configured to abort the process) and stores any other value into
135  * @c impl_type_ so that follow-up @c create_*() calls know the requested role.
136  * Subclasses typically chain @c Conf::parse() and then run their own checks.
137  *
138  * @param impl_type Role the caller intends to instantiate.
139  * @return @c true on success; the unknown-type fatal path never returns.
140  */
141  [[nodiscard]] virtual bool parse(ImplType impl_type) const;
142 
143  /**
144  * @brief Indicates whether the conf currently holds usable data.
145  *
146  * @details
147  * The base implementation returns @c false; concrete confs override it to
148  * verify that mandatory fields have been populated.
149  *
150  * @return @c true once the conf is ready to drive @c create_*() factories.
151  */
152  [[nodiscard]] virtual bool is_valid() const;
153 
154  /**
155  * @brief Returns the @c ImplType cached by the most recent @c parse() call.
156  *
157  * @return Cached @c ImplType, or @c kUnknownImplType before @c parse() runs.
158  */
159  [[nodiscard]] virtual ImplType get_impl_type() const;
160 
161  /**
162  * @brief Returns the transport backend this conf wraps.
163  *
164  * @details
165  * Default implementation returns @c TransportType::kUnknown; concrete confs
166  * (and dynamic plugins) override it to advertise their backend.
167  *
168  * @return Matching @c TransportType identifier.
169  */
170  [[nodiscard]] virtual TransportType get_transport_type() const;
171 
172  uint32_t hash_code{0}; ///< Channel / topic hash assigned by concrete backends.
173 
174  protected:
175  Conf();
176 
177  [[nodiscard]] virtual bool parse_protocol(struct Protocol* protocol);
178 
179  [[nodiscard]] virtual std::unique_ptr<class ServerImpl> create_server() const;
180 
181  [[nodiscard]] virtual std::unique_ptr<class ClientImpl> create_client() const;
182 
183  [[nodiscard]] virtual std::unique_ptr<class PublisherImpl> create_publisher() const;
184 
185  [[nodiscard]] virtual std::unique_ptr<class SubscriberImpl> create_subscriber() const;
186 
187  [[nodiscard]] virtual std::unique_ptr<class SetterImpl> create_setter() const;
188 
189  [[nodiscard]] virtual std::unique_ptr<class GetterImpl> create_getter() const;
190 
191  private:
192  friend struct Url;
193  template <typename, typename, SecurityType>
194  friend class Server;
195  template <typename, typename, SecurityType>
196  friend class Client;
197  template <typename, SecurityType>
198  friend class Publisher;
199  template <typename, SecurityType>
200  friend class Subscriber;
201  template <typename, SecurityType>
202  friend class Setter;
203  template <typename, SecurityType>
204  friend class Getter;
205 
206  mutable ImplType impl_type_{kUnknownImplType};
207 };
208 
209 } // namespace vlink
210 
211 ////////////////////////////////////////////////////////////////
212 /// Macro Definitions
213 ////////////////////////////////////////////////////////////////
214 
215 /**
216  * @def VLINK_DECLARE_CONF_FRIEND
217  * @brief Grants the six public Node<> templates friend access to the conf.
218  *
219  * @details
220  * Inject this macro into a concrete @c Conf subclass to expose the protected
221  * factory methods to @c Server, @c Client, @c Publisher, @c Subscriber,
222  * @c Setter and @c Getter. @c VLINK_CONF_IMPL already expands it; use this
223  * macro on its own only when @c VLINK_CONF_IMPL is not suitable.
224  */
225 #define VLINK_DECLARE_CONF_FRIEND() \
226  template <typename, typename, SecurityType> \
227  friend class Server; \
228  template <typename, typename, SecurityType> \
229  friend class Client; \
230  template <typename, SecurityType> \
231  friend class Publisher; \
232  template <typename, SecurityType> \
233  friend class Subscriber; \
234  template <typename, SecurityType> \
235  friend class Setter; \
236  template <typename, SecurityType> \
237  friend class Getter;
238 
239 /**
240  * @def VLINK_CONF_IMPL
241  * @brief Convenience macro that emits the standard concrete conf boilerplate.
242  *
243  * @details
244  * Expands to the friend grant, the six factory overrides, an ostream insertion
245  * operator declaration, the default constructor / destructor and an
246  * @c is_valid() override declaration whose body the subclass must provide.
247  *
248  * @param classname Subclass name being declared.
249  */
250 #define VLINK_CONF_IMPL(classname) \
251  private: \
252  VLINK_DECLARE_CONF_FRIEND() \
253  \
254  [[nodiscard]] bool parse_protocol(struct Protocol* protocol) override; \
255  \
256  [[nodiscard]] std::unique_ptr<class ServerImpl> create_server() const override; \
257  \
258  [[nodiscard]] std::unique_ptr<class ClientImpl> create_client() const override; \
259  \
260  [[nodiscard]] std::unique_ptr<class PublisherImpl> create_publisher() const override; \
261  \
262  [[nodiscard]] std::unique_ptr<class SubscriberImpl> create_subscriber() const override; \
263  \
264  [[nodiscard]] std::unique_ptr<class SetterImpl> create_setter() const override; \
265  \
266  [[nodiscard]] std::unique_ptr<class GetterImpl> create_getter() const override; \
267  \
268  VLINK_EXPORT friend std::ostream& operator<<(std::ostream& ostream, const classname& conf) noexcept; \
269  \
270  public: \
271  classname() = default; \
272  \
273  ~classname() = default; \
274  \
275  [[nodiscard]] bool is_valid() const override;
276 
277 /**
278  * @def VLINK_ALLOW_IMPL_TYPE
279  * @brief Records the bitmask of @c ImplType values supported by a conf.
280  *
281  * @details
282  * Expands to a public @c get_allow_impl_type() that returns @p type so the
283  * @c Node<> template can validate at compile time that the conf supports the
284  * requested node role. Combine roles with bitwise OR, e.g.
285  * @code
286  * VLINK_ALLOW_IMPL_TYPE(kServer | kClient | kPublisher | kSubscriber | kSetter | kGetter)
287  * @endcode
288  *
289  * @param type Bitmask of @c ImplType values supported by the conf.
290  */
291 #define VLINK_ALLOW_IMPL_TYPE(type) \
292  public: \
293  [[nodiscard]] static constexpr int get_allow_impl_type() { return type; }
294 
295 /**
296  * @def VLINK_DECLARE_GLOBAL_PROPERTY
297  * @brief Declares per-transport static configuration storage and access helpers.
298  *
299  * @details
300  * Inject into a concrete @c Conf subclass body to expose:
301  * - @c thread_count_, @c global_properties_ and @c global_mtx_ static members.
302  * - @c get_thread_count() / @c set_thread_count() accessors.
303  * - @c set_global_property() / @c get_global_property() / @c get_global_all_properties().
304  * - A @c global_init() declaration whose definition the subclass supplies.
305  *
306  * Pair with @c VLINK_DEFINE_GLOBAL_PROPERTY in the matching translation unit.
307  */
308 #define VLINK_DECLARE_GLOBAL_PROPERTY() \
309  private: \
310  static size_t thread_count_; \
311  static PropertiesMap global_properties_; \
312  static std::shared_mutex global_mtx_; \
313  \
314  public: \
315  [[nodiscard]] static size_t get_thread_count() { return thread_count_; } \
316  \
317  static void set_thread_count(size_t thread_count) { thread_count_ = thread_count; } \
318  \
319  static void set_global_property(const std::string& prop, const std::string& value) { \
320  std::lock_guard lock(global_mtx_); \
321  global_properties_[prop] = value; \
322  } \
323  \
324  [[nodiscard]] static std::string get_global_property(const std::string& prop) { \
325  std::shared_lock lock(global_mtx_); \
326  auto iter = global_properties_.find(prop); \
327  return iter != global_properties_.end() ? iter->second : std::string(); \
328  } \
329  \
330  [[nodiscard]] static PropertiesMap get_global_all_properties() { \
331  std::shared_lock lock(global_mtx_); \
332  return global_properties_; \
333  } \
334  \
335  static void global_init();
336 
337 /**
338  * @def VLINK_DEFINE_GLOBAL_PROPERTY
339  * @brief Provides storage for the statics declared by @c VLINK_DECLARE_GLOBAL_PROPERTY.
340  *
341  * @details
342  * Place once in the @c .cc file of the matching subclass. Sets
343  * @c thread_count_ to @c 1, default-constructs the property map, and
344  * default-initialises the shared mutex.
345  *
346  * @param classname Subclass that owns the static members.
347  */
348 #define VLINK_DEFINE_GLOBAL_PROPERTY(classname) \
349  size_t classname::thread_count_{1}; \
350  Conf::PropertiesMap classname::global_properties_; \
351  std::shared_mutex classname::global_mtx_;
#define VLINK_EXPORT
Definition: macros.h:81
Core enumerations and small value types shared by the entire VLink implementation layer.