1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
2 // the main distribution directory for license terms and copyright or visit
3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
4 
5 #pragma once
6 
7 #include <cstdint>
8 #include <set>
9 #include <string>
10 #include <utility>
11 
12 #include "caf/detail/core_export.hpp"
13 #include "caf/detail/is_complete.hpp"
14 #include "caf/detail/pp.hpp"
15 #include "caf/detail/squashed_int.hpp"
16 #include "caf/fwd.hpp"
17 #include "caf/string_view.hpp"
18 #include "caf/timespan.hpp"
19 #include "caf/timestamp.hpp"
20 
21 namespace caf {
22 
23 /// Internal representation of a type ID.
24 using type_id_t = uint16_t;
25 
26 /// Special value equal to the greatest possible value for `type_id_t`.
27 /// Generally indicates that no type ID for a given type exists.
28 constexpr type_id_t invalid_type_id = 65535;
29 
30 /// Maps the type `T` to a globally unique ID.
31 template <class T>
32 struct type_id;
33 
34 /// Convenience alias for `type_id<T>::value`.
35 /// @relates type_id
36 template <class T>
37 constexpr type_id_t type_id_v = type_id<detail::squash_if_int_t<T>>::value;
38 
39 /// Maps the globally unique ID `V` to a type (inverse to ::type_id).
40 /// @relates type_id
41 template <type_id_t V>
42 struct type_by_id;
43 
44 /// Convenience alias for `type_by_id<I>::type`.
45 /// @relates type_by_id
46 template <type_id_t I>
47 using type_by_id_t = typename type_by_id<I>::type;
48 
49 /// Maps the globally unique ID `V` to a type name.
50 template <type_id_t V>
51 struct type_name_by_id;
52 
53 /// Convenience alias for `type_name_by_id<I>::value`.
54 /// @relates type_name_by_id
55 template <type_id_t I>
56 constexpr string_view type_name_by_id_v = type_name_by_id<I>::value;
57 
58 /// Convenience type that resolves to `type_name_by_id<type_id_v<T>>`.
59 template <class T>
60 struct type_name;
61 
62 /// Convenience specialization that enables generic code to not treat `void`
63 /// manually.
64 template <>
65 struct type_name<void> {
66   static constexpr string_view value = "void";
67 };
68 
69 /// Convenience alias for `type_name<T>::value`.
70 /// @relates type_name
71 template <class T>
72 constexpr string_view type_name_v = type_name<T>::value;
73 
74 /// The first type ID not reserved by CAF and its modules.
75 constexpr type_id_t first_custom_type_id = 200;
76 
77 /// Checks whether `type_id` is specialized for `T`.
78 template <class T>
79 constexpr bool has_type_id_v = detail::is_complete<type_id<T>>;
80 
81 // TODO: remove with CAF 0.19 (this exists for compatibility with CAF 0.17).
82 template <class T>
83 struct has_type_id {
84   static constexpr bool value = detail::is_complete<type_id<T>>;
85 };
86 
87 /// Returns `type_name_v<T>` if available, "anonymous" otherwise.
88 template <class T>
type_name_or_anonymous()89 string_view type_name_or_anonymous() {
90   if constexpr (detail::is_complete<type_name<T>>)
91     return type_name<T>::value;
92   else
93     return "anonymous";
94 }
95 
96 /// Returns `type_id_v<T>` if available, `invalid_type_id` otherwise.
97 template <class T>
type_id_or_invalid()98 type_id_t type_id_or_invalid() {
99   if constexpr (detail::is_complete<type_id<T>>)
100     return type_id<T>::value;
101   else
102     return invalid_type_id;
103 }
104 
105 /// Returns the type name of given `type` or an empty string if `type` is an
106 /// invalid ID.
107 CAF_CORE_EXPORT string_view query_type_name(type_id_t type);
108 
109 /// Returns the type of given `name` or `invalid_type_id` if no type matches.
110 CAF_CORE_EXPORT type_id_t query_type_id(string_view name);
111 
112 } // namespace caf
113 
114 // -- CAF_BEGIN_TYPE_ID_BLOCK --------------------------------------------------
115 
116 /// Starts a code block for registering custom types to CAF. Stores the first ID
117 /// for the project as `caf::id_block::${project_name}_first_type_id`. Usually,
118 /// users should use `caf::first_custom_type_id` as `first_id`. However, this
119 /// mechanism also enables projects to append IDs to a block of another project.
120 /// If two projects are developed separately to avoid dependencies, they only
121 /// need to define sufficiently large offsets to guarantee collision-free IDs.
122 /// CAF supports gaps in the ID space.
123 ///
124 /// @note CAF reserves all names with the suffix `_module`. For example, core
125 ///       module uses the project name `core_module`.
126 #define CAF_BEGIN_TYPE_ID_BLOCK(project_name, first_id)                        \
127   namespace caf::id_block {                                                    \
128   constexpr type_id_t project_name##_type_id_counter_init = __COUNTER__;       \
129   constexpr type_id_t project_name##_first_type_id = first_id;                 \
130   }
131 
132 // -- CAF_ADD_TYPE_ID ----------------------------------------------------------
133 
134 #ifdef CAF_MSVC
135 #  define CAF_DETAIL_NEXT_TYPE_ID(project_name, fully_qualified_name)          \
136     template <>                                                                \
137     struct type_id<::CAF_PP_EXPAND fully_qualified_name> {                     \
138       static constexpr type_id_t value                                         \
139         = id_block::project_name##_first_type_id                               \
140           + (CAF_PP_CAT(CAF_PP_COUNTER, ())                                    \
141              - id_block::project_name##_type_id_counter_init - 1);             \
142     };
143 #else
144 #  define CAF_DETAIL_NEXT_TYPE_ID(project_name, fully_qualified_name)          \
145     template <>                                                                \
146     struct type_id<::CAF_PP_EXPAND fully_qualified_name> {                     \
147       static constexpr type_id_t value                                         \
148         = id_block::project_name##_first_type_id                               \
149           + (__COUNTER__ - id_block::project_name##_type_id_counter_init - 1); \
150     };
151 #endif
152 
153 #define CAF_ADD_TYPE_ID_2(project_name, fully_qualified_name)                  \
154   namespace caf {                                                              \
155   CAF_DETAIL_NEXT_TYPE_ID(project_name, fully_qualified_name)                  \
156   template <>                                                                  \
157   struct type_by_id<type_id<::CAF_PP_EXPAND fully_qualified_name>::value> {    \
158     using type = ::CAF_PP_EXPAND fully_qualified_name;                         \
159   };                                                                           \
160   template <>                                                                  \
161   struct type_name<::CAF_PP_EXPAND fully_qualified_name> {                     \
162     static constexpr string_view value                                         \
163       = CAF_PP_STR(CAF_PP_EXPAND fully_qualified_name);                        \
164   };                                                                           \
165   template <>                                                                  \
166   struct type_name_by_id<type_id<::CAF_PP_EXPAND fully_qualified_name>::value> \
167     : type_name<::CAF_PP_EXPAND fully_qualified_name> {};                      \
168   }
169 
170 #define CAF_ADD_TYPE_ID_3(project_name, fully_qualified_name, user_type_name)  \
171   namespace caf {                                                              \
172   CAF_DETAIL_NEXT_TYPE_ID(project_name, fully_qualified_name)                  \
173   template <>                                                                  \
174   struct type_by_id<type_id<::CAF_PP_EXPAND fully_qualified_name>::value> {    \
175     using type = ::CAF_PP_EXPAND fully_qualified_name;                         \
176   };                                                                           \
177   template <>                                                                  \
178   struct type_name<::CAF_PP_EXPAND fully_qualified_name> {                     \
179     static constexpr string_view value = user_type_name;                       \
180   };                                                                           \
181   template <>                                                                  \
182   struct type_name_by_id<type_id<::CAF_PP_EXPAND fully_qualified_name>::value> \
183     : type_name<::CAF_PP_EXPAND fully_qualified_name> {};                      \
184   }
185 
186 /// @def CAF_ADD_TYPE_ID(project_name, fully_qualified_name, user_type_name)
187 /// Assigns the next free type ID to `fully_qualified_name`.
188 /// @param project_name User-defined name for type ID block.
189 /// @param fully_qualified_name Name of the type enclosed in parens and
190 ///                             including namespaces, e.g., `(std::string)`.
191 /// @param user_type_name Optional parameter. If present, defines the content of
192 ///                       `caf::type_name`. Defaults to `fully_qualified_name`.
193 #ifdef CAF_MSVC
194 #  define CAF_ADD_TYPE_ID(...)                                                 \
195     CAF_PP_CAT(CAF_PP_OVERLOAD(CAF_ADD_TYPE_ID_, __VA_ARGS__)(__VA_ARGS__),    \
196                CAF_PP_EMPTY())
197 #else
198 #  define CAF_ADD_TYPE_ID(...)                                                 \
199     CAF_PP_OVERLOAD(CAF_ADD_TYPE_ID_, __VA_ARGS__)(__VA_ARGS__)
200 #endif
201 
202 // -- CAF_ADD_TYPE_ID_FROM_EXPR ------------------------------------------------
203 
204 #ifdef CAF_MSVC
205 #  define CAF_DETAIL_NEXT_TYPE_ID_FROM_EXPR(project_name, type_expr)           \
206     template <>                                                                \
207     struct type_id<CAF_PP_EXPAND type_expr> {                                  \
208       static constexpr type_id_t value                                         \
209         = id_block::project_name##_first_type_id                               \
210           + (CAF_PP_CAT(CAF_PP_COUNTER, ())                                    \
211              - id_block::project_name##_type_id_counter_init - 1);             \
212     };
213 #else
214 #  define CAF_DETAIL_NEXT_TYPE_ID_FROM_EXPR(project_name, type_expr)           \
215     template <>                                                                \
216     struct type_id<CAF_PP_EXPAND type_expr> {                                  \
217       static constexpr type_id_t value                                         \
218         = id_block::project_name##_first_type_id                               \
219           + (__COUNTER__ - id_block::project_name##_type_id_counter_init - 1); \
220     };
221 #endif
222 
223 #define CAF_ADD_TYPE_ID_FROM_EXPR_2(project_name, type_expr)                   \
224   namespace caf {                                                              \
225   CAF_DETAIL_NEXT_TYPE_ID_FROM_EXPR(project_name, type_expr)                   \
226   template <>                                                                  \
227   struct type_by_id<type_id<CAF_PP_EXPAND type_expr>::value> {                 \
228     using type = CAF_PP_EXPAND type_expr;                                      \
229   };                                                                           \
230   template <>                                                                  \
231   struct type_name<CAF_PP_EXPAND type_expr> {                                  \
232     static constexpr string_view value = CAF_PP_STR(CAF_PP_EXPAND type_expr);  \
233   };                                                                           \
234   template <>                                                                  \
235   struct type_name_by_id<type_id<CAF_PP_EXPAND type_expr>::value>              \
236     : type_name<CAF_PP_EXPAND type_expr> {};                                   \
237   }
238 
239 #define CAF_ADD_TYPE_ID_FROM_EXPR_3(project_name, type_expr, user_type_name)   \
240   namespace caf {                                                              \
241   CAF_DETAIL_NEXT_TYPE_ID_FROM_EXPR(project_name, type_expr)                   \
242   template <>                                                                  \
243   struct type_by_id<type_id<CAF_PP_EXPAND type_expr>::value> {                 \
244     using type = CAF_PP_EXPAND type_expr;                                      \
245   };                                                                           \
246   template <>                                                                  \
247   struct type_name<CAF_PP_EXPAND type_expr> {                                  \
248     static constexpr string_view value = user_type_name;                       \
249   };                                                                           \
250   template <>                                                                  \
251   struct type_name_by_id<type_id<CAF_PP_EXPAND type_expr>::value>              \
252     : type_name<CAF_PP_EXPAND type_expr> {};                                   \
253   }
254 
255 /// @def CAF_ADD_TYPE_ID_FROM_EXPR(project_name, type_expr, user_type_name)
256 /// Assigns the next free type ID to the type resulting from `type_expr`.
257 /// @param project_name User-defined name for type ID block.
258 /// @param type_expr A compile-time expression resulting in a type, e.g., a
259 ///                  `decltype` statement.
260 /// @param user_type_name Optional parameter. If present, defines the content of
261 ///                       `caf::type_name`. Defaults to `type_expr`.
262 #ifdef CAF_MSVC
263 #  define CAF_ADD_TYPE_ID_FROM_EXPR(...)                                       \
264     CAF_PP_CAT(CAF_PP_OVERLOAD(CAF_ADD_TYPE_ID_FROM_EXPR_,                     \
265                                __VA_ARGS__)(__VA_ARGS__),                      \
266                CAF_PP_EMPTY())
267 #else
268 #  define CAF_ADD_TYPE_ID_FROM_EXPR(...)                                       \
269     CAF_PP_OVERLOAD(CAF_ADD_TYPE_ID_FROM_EXPR_, __VA_ARGS__)(__VA_ARGS__)
270 #endif
271 
272 // -- CAF_ADD_ATOM -------------------------------------------------------------
273 
274 /// Creates a new tag type (atom) in the global namespace and assigns the next
275 /// free type ID to it.
276 #define CAF_ADD_ATOM_2(project_name, atom_name)                                \
277   struct atom_name {};                                                         \
278   static constexpr atom_name atom_name##_v = atom_name{};                      \
279   [[maybe_unused]] constexpr bool operator==(atom_name, atom_name) {           \
280     return true;                                                               \
281   }                                                                            \
282   [[maybe_unused]] constexpr bool operator!=(atom_name, atom_name) {           \
283     return false;                                                              \
284   }                                                                            \
285   template <class Inspector>                                                   \
286   bool inspect(Inspector& f, atom_name& x) {                                   \
287     return f.object(x).fields();                                               \
288   }                                                                            \
289   CAF_ADD_TYPE_ID(project_name, (atom_name))
290 
291 /// Creates a new tag type (atom) and assigns the next free type ID to it.
292 #define CAF_ADD_ATOM_3(project_name, atom_namespace, atom_name)                \
293   namespace atom_namespace {                                                   \
294   struct atom_name {};                                                         \
295   static constexpr atom_name atom_name##_v = atom_name{};                      \
296   [[maybe_unused]] constexpr bool operator==(atom_name, atom_name) {           \
297     return true;                                                               \
298   }                                                                            \
299   [[maybe_unused]] constexpr bool operator!=(atom_name, atom_name) {           \
300     return false;                                                              \
301   }                                                                            \
302   template <class Inspector>                                                   \
303   bool inspect(Inspector& f, atom_name& x) {                                   \
304     return f.object(x).fields();                                               \
305   }                                                                            \
306   }                                                                            \
307   CAF_ADD_TYPE_ID(project_name, (atom_namespace::atom_name))
308 
309 /// Creates a new tag type (atom) and assigns the next free type ID to it.
310 #define CAF_ADD_ATOM_4(project_name, atom_namespace, atom_name, atom_text)     \
311   namespace atom_namespace {                                                   \
312   struct atom_name {};                                                         \
313   static constexpr atom_name atom_name##_v = atom_name{};                      \
314   [[maybe_unused]] constexpr bool operator==(atom_name, atom_name) {           \
315     return true;                                                               \
316   }                                                                            \
317   [[maybe_unused]] constexpr bool operator!=(atom_name, atom_name) {           \
318     return false;                                                              \
319   }                                                                            \
320   inline std::string to_string(atom_name) {                                    \
321     return atom_text;                                                          \
322   }                                                                            \
323   template <class Inspector>                                                   \
324   auto inspect(Inspector& f, atom_name& x) {                                   \
325     return f.object(x).fields();                                               \
326   }                                                                            \
327   }                                                                            \
328   CAF_ADD_TYPE_ID(project_name, (atom_namespace::atom_name))
329 
330 #ifdef CAF_MSVC
331 #  define CAF_ADD_ATOM(...)                                                    \
332     CAF_PP_CAT(CAF_PP_OVERLOAD(CAF_ADD_ATOM_, __VA_ARGS__)(__VA_ARGS__),       \
333                CAF_PP_EMPTY())
334 #else
335 #  define CAF_ADD_ATOM(...)                                                    \
336     CAF_PP_OVERLOAD(CAF_ADD_ATOM_, __VA_ARGS__)(__VA_ARGS__)
337 #endif
338 
339 // -- CAF_END_TYPE_ID_BLOCK ----------------------------------------------------
340 
341 /// Finalizes a code block for registering custom types to CAF. Defines a struct
342 /// `caf::type_id::${project_name}` with two static members `begin` and `end`.
343 /// The former stores the first assigned type ID. The latter stores the last
344 /// assigned type ID + 1.
345 #define CAF_END_TYPE_ID_BLOCK(project_name)                                    \
346   namespace caf::id_block {                                                    \
347   constexpr type_id_t project_name##_last_type_id                              \
348     = project_name##_first_type_id                                             \
349       + (__COUNTER__ - project_name##_type_id_counter_init - 2);               \
350   struct project_name {                                                        \
351     static constexpr type_id_t begin = project_name##_first_type_id;           \
352     static constexpr type_id_t end = project_name##_last_type_id + 1;          \
353   };                                                                           \
354   }
355 
356 // -- type ID block for the core module ----------------------------------------
357 
358 CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
359 
360   // -- C types
361 
362   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (bool) )
363   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (double) )
364   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (float) )
365   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (int16_t))
366   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (int32_t))
367   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (int64_t))
368   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (int8_t))
369   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (long double), "ldouble")
370   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (uint16_t))
371   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (uint32_t))
372   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (uint64_t))
373   CAF_ADD_TYPE_ID_FROM_EXPR(core_module, (uint8_t))
374 
375   // -- STL types
376 
377   CAF_ADD_TYPE_ID(core_module, (std::string))
378   CAF_ADD_TYPE_ID(core_module, (std::u16string))
379   CAF_ADD_TYPE_ID(core_module, (std::u32string))
380   CAF_ADD_TYPE_ID(core_module, (std::set<std::string>) )
381 
382   // -- CAF types
383 
384   CAF_ADD_TYPE_ID(core_module, (caf::actor))
385   CAF_ADD_TYPE_ID(core_module, (caf::actor_addr))
386   CAF_ADD_TYPE_ID(core_module, (caf::byte_buffer))
387   CAF_ADD_TYPE_ID(core_module, (caf::config_value))
388   CAF_ADD_TYPE_ID(core_module, (caf::dictionary<caf::config_value>) )
389   CAF_ADD_TYPE_ID(core_module, (caf::down_msg))
390   CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg))
391   CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg_batch))
392   CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg_close))
393   CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg_forced_close))
394   CAF_ADD_TYPE_ID(core_module, (caf::error))
395   CAF_ADD_TYPE_ID(core_module, (caf::exit_msg))
396   CAF_ADD_TYPE_ID(core_module, (caf::exit_reason))
397   CAF_ADD_TYPE_ID(core_module, (caf::group))
398   CAF_ADD_TYPE_ID(core_module, (caf::group_down_msg))
399   CAF_ADD_TYPE_ID(core_module, (caf::hashed_node_id))
400   CAF_ADD_TYPE_ID(core_module, (caf::ipv4_address))
401   CAF_ADD_TYPE_ID(core_module, (caf::ipv4_endpoint))
402   CAF_ADD_TYPE_ID(core_module, (caf::ipv4_subnet))
403   CAF_ADD_TYPE_ID(core_module, (caf::ipv6_address))
404   CAF_ADD_TYPE_ID(core_module, (caf::ipv6_endpoint))
405   CAF_ADD_TYPE_ID(core_module, (caf::ipv6_subnet))
406   CAF_ADD_TYPE_ID(core_module, (caf::message))
407   CAF_ADD_TYPE_ID(core_module, (caf::message_id))
408   CAF_ADD_TYPE_ID(core_module, (caf::node_down_msg))
409   CAF_ADD_TYPE_ID(core_module, (caf::node_id))
410   CAF_ADD_TYPE_ID(core_module, (caf::none_t))
411   CAF_ADD_TYPE_ID(core_module, (caf::open_stream_msg))
412   CAF_ADD_TYPE_ID(core_module, (caf::pec))
413   CAF_ADD_TYPE_ID(core_module, (caf::sec))
414   CAF_ADD_TYPE_ID(core_module, (caf::stream_slots))
415   CAF_ADD_TYPE_ID(core_module, (caf::strong_actor_ptr))
416   CAF_ADD_TYPE_ID(core_module, (caf::timeout_msg))
417   CAF_ADD_TYPE_ID(core_module, (caf::timespan))
418   CAF_ADD_TYPE_ID(core_module, (caf::timestamp))
419   CAF_ADD_TYPE_ID(core_module, (caf::unit_t))
420   CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg))
421   CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_ack_batch))
422   CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_ack_open))
423   CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_drop))
424   CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_forced_drop))
425   CAF_ADD_TYPE_ID(core_module, (caf::uri))
426   CAF_ADD_TYPE_ID(core_module, (caf::weak_actor_ptr))
427   CAF_ADD_TYPE_ID(core_module, (std::vector<caf::actor>) )
428   CAF_ADD_TYPE_ID(core_module, (std::vector<caf::actor_addr>) )
429   CAF_ADD_TYPE_ID(core_module, (std::vector<caf::config_value>) )
430   CAF_ADD_TYPE_ID(core_module, (std::vector<caf::strong_actor_ptr>) )
431   CAF_ADD_TYPE_ID(core_module, (std::vector<caf::weak_actor_ptr>) )
432   CAF_ADD_TYPE_ID(core_module, (std::vector<std::pair<std::string, message>>) )
433 
434   // -- predefined atoms
435 
436   CAF_ADD_ATOM(core_module, caf, add_atom)
437   CAF_ADD_ATOM(core_module, caf, close_atom)
438   CAF_ADD_ATOM(core_module, caf, connect_atom)
439   CAF_ADD_ATOM(core_module, caf, contact_atom)
440   CAF_ADD_ATOM(core_module, caf, delete_atom)
441   CAF_ADD_ATOM(core_module, caf, demonitor_atom)
442   CAF_ADD_ATOM(core_module, caf, div_atom)
443   CAF_ADD_ATOM(core_module, caf, flush_atom)
444   CAF_ADD_ATOM(core_module, caf, forward_atom)
445   CAF_ADD_ATOM(core_module, caf, get_atom)
446   CAF_ADD_ATOM(core_module, caf, group_atom)
447   CAF_ADD_ATOM(core_module, caf, idle_atom)
448   CAF_ADD_ATOM(core_module, caf, join_atom)
449   CAF_ADD_ATOM(core_module, caf, leave_atom)
450   CAF_ADD_ATOM(core_module, caf, link_atom)
451   CAF_ADD_ATOM(core_module, caf, migrate_atom)
452   CAF_ADD_ATOM(core_module, caf, monitor_atom)
453   CAF_ADD_ATOM(core_module, caf, mul_atom)
454   CAF_ADD_ATOM(core_module, caf, ok_atom)
455   CAF_ADD_ATOM(core_module, caf, open_atom)
456   CAF_ADD_ATOM(core_module, caf, pending_atom)
457   CAF_ADD_ATOM(core_module, caf, ping_atom)
458   CAF_ADD_ATOM(core_module, caf, pong_atom)
459   CAF_ADD_ATOM(core_module, caf, publish_atom)
460   CAF_ADD_ATOM(core_module, caf, publish_udp_atom)
461   CAF_ADD_ATOM(core_module, caf, put_atom)
462   CAF_ADD_ATOM(core_module, caf, receive_atom)
463   CAF_ADD_ATOM(core_module, caf, redirect_atom)
464   CAF_ADD_ATOM(core_module, caf, registry_lookup_atom)
465   CAF_ADD_ATOM(core_module, caf, reset_atom)
466   CAF_ADD_ATOM(core_module, caf, resolve_atom)
467   CAF_ADD_ATOM(core_module, caf, spawn_atom)
468   CAF_ADD_ATOM(core_module, caf, stream_atom)
469   CAF_ADD_ATOM(core_module, caf, sub_atom)
470   CAF_ADD_ATOM(core_module, caf, subscribe_atom)
471   CAF_ADD_ATOM(core_module, caf, sys_atom)
472   CAF_ADD_ATOM(core_module, caf, tick_atom)
473   CAF_ADD_ATOM(core_module, caf, timeout_atom)
474   CAF_ADD_ATOM(core_module, caf, unlink_atom)
475   CAF_ADD_ATOM(core_module, caf, unpublish_atom)
476   CAF_ADD_ATOM(core_module, caf, unpublish_udp_atom)
477   CAF_ADD_ATOM(core_module, caf, unsubscribe_atom)
478   CAF_ADD_ATOM(core_module, caf, update_atom)
479   CAF_ADD_ATOM(core_module, caf, wait_for_atom)
480 
481 CAF_END_TYPE_ID_BLOCK(core_module)
482 
483 namespace caf::detail {
484 
485 static constexpr type_id_t io_module_begin = id_block::core_module::end;
486 
487 static constexpr type_id_t io_module_end = io_module_begin + 19;
488 
489 static constexpr type_id_t net_module_begin = io_module_end;
490 
491 static constexpr type_id_t net_module_end = net_module_begin + 1;
492 
493 static_assert(net_module_end <= first_custom_type_id);
494 
495 } // namespace caf::detail
496