SEDSnet 4.0.1

A memory safe, no_std-capable networking stack with routing, discovery, reliability, and Rust/C/Python bindings.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
#ifndef SEDSNET_C_WRAPPER_H
#define SEDSNET_C_WRAPPER_H

#include "sedsnet.h"
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct SedsWrapperRouterConfig
{
    SedsRouterMode mode;
    SedsNowMsFn now_ms;
    void * now_user;
    const SedsLocalEndpointDesc * handlers;
    size_t num_handlers;
    SedsName sender;
    uint8_t e2e_mode;
    uint32_t e2e_key_id;

    bool configure_timesync;
    uint32_t timesync_role;
    uint64_t timesync_priority;
    uint64_t timesync_source_timeout_ms;
    uint64_t timesync_announce_interval_ms;
    uint64_t timesync_request_interval_ms;

    bool announce_discovery;
} SedsWrapperRouterConfig;

typedef struct SedsWrapperRouter
{
    SedsRouter * router;
    uint8_t created;
    uint64_t start_time_ms;
    SedsSideRef primary_side;
    int32_t init_error;
} SedsWrapperRouter;

typedef struct SedsWrapperRelayConfig
{
    SedsNowMsFn now_ms;
    void * now_user;
    SedsName sender;
    bool announce_discovery;
} SedsWrapperRelayConfig;

typedef struct SedsWrapperRelay
{
    SedsRelay * relay;
    uint8_t created;
    SedsSideRef primary_side;
    int32_t init_error;
} SedsWrapperRelay;

SedsWrapperRouterConfig seds_wrapper_router_default_config(void);
SedsWrapperRelayConfig seds_wrapper_relay_default_config(void);

SedsResult seds_wrapper_router_init(SedsWrapperRouter * node,
                                    const SedsWrapperRouterConfig * cfg);
void seds_wrapper_router_free(SedsWrapperRouter * node);

SedsRouter * seds_wrapper_router_handle(SedsWrapperRouter * node);
int32_t seds_wrapper_router_init_error(const SedsWrapperRouter * node);
SedsRouter * seds_global_router_handle(void);
int32_t seds_global_router_init_error(void);
SedsResult seds_global_router_init(const SedsWrapperRouterConfig * cfg);
void seds_global_router_free(void);

SedsSideRef seds_wrapper_router_add_packed_side(SedsWrapperRouter * node,
                                                    SedsName name,
                                                    SedsTransmitFn tx,
                                                    void * tx_user,
                                                    bool reliable_enabled);
SedsSideRef seds_wrapper_router_add_packed_small_side(SedsWrapperRouter * node,
                                                          SedsName name,
                                                          SedsTransmitFn tx,
                                                          void * tx_user,
                                                          bool reliable_enabled,
                                                          size_t max_frame_bytes);
SedsSideRef seds_wrapper_router_add_packet_side(SedsWrapperRouter * node,
                                                SedsName name,
                                                SedsEndpointHandlerFn tx,
                                                void * tx_user,
                                                bool reliable_enabled);
SedsSideRef seds_global_router_add_packed_side(SedsName name,
                                                   SedsTransmitFn tx,
                                                   void * tx_user,
                                                   bool reliable_enabled);
SedsSideRef seds_global_router_add_packed_small_side(SedsName name,
                                                         SedsTransmitFn tx,
                                                         void * tx_user,
                                                         bool reliable_enabled,
                                                         size_t max_frame_bytes);
SedsSideRef seds_global_router_add_packet_side(SedsName name,
                                               SedsEndpointHandlerFn tx,
                                               void * tx_user,
                                               bool reliable_enabled);
SedsResult seds_global_router_remove_side(SedsSideRef side);
SedsResult seds_global_router_set_side_ingress_enabled(SedsSideRef side, bool enabled);
SedsResult seds_global_router_set_side_egress_enabled(SedsSideRef side, bool enabled);
SedsResult seds_global_router_set_route(SedsSideRef src_side, SedsSideRef dst_side, bool enabled);
SedsResult seds_global_router_clear_route(SedsSideRef src_side, SedsSideRef dst_side);
SedsResult seds_global_router_set_typed_route(SedsSideRef src_side, SedsTypeRef ty, SedsSideRef dst_side, bool enabled);
SedsResult seds_global_router_clear_typed_route(SedsSideRef src_side, SedsTypeRef ty, SedsSideRef dst_side);
SedsResult seds_global_router_set_source_route_mode(SedsSideRef src_side, SedsRouteSelectionMode mode);
SedsResult seds_global_router_clear_source_route_mode(SedsSideRef src_side);
SedsResult seds_global_router_set_route_weight(SedsSideRef src_side, SedsSideRef dst_side, uint32_t weight);
SedsResult seds_global_router_clear_route_weight(SedsSideRef src_side, SedsSideRef dst_side);
SedsResult seds_global_router_set_route_priority(SedsSideRef src_side, SedsSideRef dst_side, uint32_t priority);
SedsResult seds_global_router_clear_route_priority(SedsSideRef src_side, SedsSideRef dst_side);

SedsResult seds_wrapper_router_rx_packed(SedsWrapperRouter * node,
                                             const uint8_t * bytes,
                                             size_t len);
SedsResult seds_wrapper_router_rx_packed_from_side(SedsWrapperRouter * node,
                                                       SedsSideRef side,
                                                       const uint8_t * bytes,
                                                       size_t len);
SedsResult seds_global_router_rx_packed(const uint8_t * bytes, size_t len);
SedsResult seds_global_router_rx_packed_from_side(SedsSideRef side,
                                                      const uint8_t * bytes,
                                                      size_t len);

SedsResult seds_wrapper_router_process(SedsWrapperRouter * node, uint32_t timeout_ms);
SedsResult seds_wrapper_router_periodic(SedsWrapperRouter * node, uint32_t timeout_ms);
SedsResult seds_wrapper_router_poll_timesync(SedsWrapperRouter * node, bool * out_did_queue);
SedsResult seds_wrapper_router_announce_discovery(SedsWrapperRouter * node);
SedsResult seds_wrapper_router_announce_leave(SedsWrapperRouter * node);
SedsResult seds_wrapper_router_poll_discovery(SedsWrapperRouter * node, bool * out_did_queue);
SedsResult seds_wrapper_router_enable_managed_variable(SedsWrapperRouter * node, SedsTypeRef ty);
SedsResult seds_wrapper_router_enable_network_variable(SedsWrapperRouter * node,
                                                       SedsTypeRef ty,
                                                       bool can_read,
                                                       bool can_write);
SedsResult seds_wrapper_router_on_network_variable_update(SedsWrapperRouter * node,
                                                          SedsTypeRef ty,
                                                          SedsEndpointHandlerFn cb,
                                                          void * user);
void seds_wrapper_router_disable_managed_variable(SedsWrapperRouter * node, SedsTypeRef ty);
SedsResult seds_wrapper_router_request_managed_variable(SedsWrapperRouter * node, SedsTypeRef ty);
SedsResult seds_wrapper_router_set_network_variable_packed(SedsWrapperRouter * node,
                                                               const uint8_t * bytes,
                                                               size_t len);
SedsResult seds_wrapper_router_seed_managed_variable_packed(SedsWrapperRouter * node,
                                                                const uint8_t * bytes,
                                                                size_t len);
int32_t seds_wrapper_router_cached_managed_variable_packed_len(SedsWrapperRouter * node,
                                                                   SedsTypeRef ty);
int32_t seds_wrapper_router_cached_managed_variable_packed(SedsWrapperRouter * node,
                                                               SedsTypeRef ty,
                                                               uint8_t * out,
                                                               size_t out_len);
int32_t seds_wrapper_router_get_network_variable_packed_len(SedsWrapperRouter * node,
                                                                SedsTypeRef ty,
                                                                uint32_t stale_after_ms);
int32_t seds_wrapper_router_get_network_variable_packed(SedsWrapperRouter * node,
                                                            SedsTypeRef ty,
                                                            uint32_t stale_after_ms,
                                                            uint8_t * out,
                                                            size_t out_len);
SedsResult seds_global_router_process(uint32_t timeout_ms);
SedsResult seds_global_router_periodic(uint32_t timeout_ms);
SedsResult seds_global_router_periodic_no_timesync(uint32_t timeout_ms);
SedsResult seds_global_router_poll_timesync(bool * out_did_queue);
SedsResult seds_global_router_announce_discovery(void);
SedsResult seds_global_router_announce_leave(void);
SedsResult seds_global_router_poll_discovery(bool * out_did_queue);
SedsResult seds_global_router_enable_managed_variable(SedsTypeRef ty);
SedsResult seds_global_router_enable_network_variable(SedsTypeRef ty, bool can_read, bool can_write);
SedsResult seds_global_router_on_network_variable_update(SedsTypeRef ty,
                                                         SedsEndpointHandlerFn cb,
                                                         void * user);
void seds_global_router_disable_managed_variable(SedsTypeRef ty);
SedsResult seds_global_router_request_managed_variable(SedsTypeRef ty);
SedsResult seds_global_router_set_network_variable_packed(const uint8_t * bytes, size_t len);
SedsResult seds_global_router_seed_managed_variable_packed(const uint8_t * bytes, size_t len);
int32_t seds_global_router_cached_managed_variable_packed_len(SedsTypeRef ty);
int32_t seds_global_router_cached_managed_variable_packed(SedsTypeRef ty,
                                                              uint8_t * out,
                                                              size_t out_len);
int32_t seds_global_router_get_network_variable_packed_len(SedsTypeRef ty,
                                                               uint32_t stale_after_ms);
int32_t seds_global_router_get_network_variable_packed(SedsTypeRef ty,
                                                           uint32_t stale_after_ms,
                                                           uint8_t * out,
                                                           size_t out_len);
SedsResult seds_global_router_get_network_time_ms(uint64_t * out_ms);
SedsResult seds_global_router_get_network_time(SedsNetworkTime * out);
int32_t seds_global_router_export_topology_len(void);
SedsResult seds_global_router_export_topology(char * buf, size_t buf_len);
int32_t seds_global_router_export_client_stats_len(SedsName sender);
SedsResult seds_global_router_export_client_stats(SedsName sender, char * buf, size_t buf_len);
int32_t seds_global_router_export_runtime_stats_len(void);
SedsResult seds_global_router_export_runtime_stats(char * buf, size_t buf_len);
int32_t seds_global_router_export_memory_layout_len(void);
SedsResult seds_global_router_export_memory_layout(char * buf, size_t buf_len);

SedsResult seds_wrapper_router_log_typed(SedsWrapperRouter * node,
                                         SedsTypeRef ty,
                                         const void * data,
                                         size_t count,
                                         size_t elem_size,
                                         SedsElemKind elem_kind,
                                         const uint64_t * timestamp_ms_opt,
                                         int queue);
SedsResult seds_wrapper_router_log_string(SedsWrapperRouter * node,
                                          SedsTypeRef ty,
                                          const char * text,
                                          const uint64_t * timestamp_ms_opt,
                                          int queue);
SedsResult seds_global_router_log_typed(SedsTypeRef ty,
                                        const void * data,
                                        size_t count,
                                        size_t elem_size,
                                        SedsElemKind elem_kind,
                                        const uint64_t * timestamp_ms_opt,
                                        int queue);
SedsResult seds_global_router_log_string(SedsTypeRef ty,
                                         const char * text,
                                         const uint64_t * timestamp_ms_opt,
                                         int queue);

SedsResult seds_wrapper_relay_init(SedsWrapperRelay * node,
                                   const SedsWrapperRelayConfig * cfg);
void seds_wrapper_relay_free(SedsWrapperRelay * node);
SedsRelay * seds_wrapper_relay_handle(SedsWrapperRelay * node);
int32_t seds_wrapper_relay_init_error(const SedsWrapperRelay * node);
SedsRelay * seds_global_relay_handle(void);
int32_t seds_global_relay_init_error(void);
SedsResult seds_global_relay_init(const SedsWrapperRelayConfig * cfg);
void seds_global_relay_free(void);

SedsSideRef seds_wrapper_relay_add_packed_side(SedsWrapperRelay * node,
                                                   SedsName name,
                                                   SedsTransmitFn tx,
                                                   void * tx_user,
                                                   bool reliable_enabled);
SedsSideRef seds_wrapper_relay_add_packed_small_side(SedsWrapperRelay * node,
                                                         SedsName name,
                                                         SedsTransmitFn tx,
                                                         void * tx_user,
                                                         bool reliable_enabled,
                                                         size_t max_frame_bytes);
SedsSideRef seds_wrapper_relay_add_packet_side(SedsWrapperRelay * node,
                                               SedsName name,
                                               SedsEndpointHandlerFn tx,
                                               void * tx_user,
                                               bool reliable_enabled);
SedsSideRef seds_global_relay_add_packed_side(SedsName name,
                                                  SedsTransmitFn tx,
                                                  void * tx_user,
                                                  bool reliable_enabled);
SedsSideRef seds_global_relay_add_packed_small_side(SedsName name,
                                                        SedsTransmitFn tx,
                                                        void * tx_user,
                                                        bool reliable_enabled,
                                                        size_t max_frame_bytes);
SedsSideRef seds_global_relay_add_packet_side(SedsName name,
                                              SedsEndpointHandlerFn tx,
                                              void * tx_user,
                                              bool reliable_enabled);

SedsResult seds_wrapper_relay_rx_packed_from_side(SedsWrapperRelay * node,
                                                      SedsSideRef side,
                                                      const uint8_t * bytes,
                                                      size_t len);
SedsResult seds_wrapper_relay_rx_packet_from_side(SedsWrapperRelay * node,
                                                  SedsSideRef side,
                                                  const SedsPacketView * view);
SedsResult seds_global_relay_rx_packed_from_side(SedsSideRef side,
                                                     const uint8_t * bytes,
                                                     size_t len);
SedsResult seds_global_relay_rx_packet_from_side(SedsSideRef side,
                                                 const SedsPacketView * view);

SedsResult seds_wrapper_relay_process(SedsWrapperRelay * node, uint32_t timeout_ms);
SedsResult seds_wrapper_relay_periodic(SedsWrapperRelay * node, uint32_t timeout_ms);
SedsResult seds_wrapper_relay_announce_discovery(SedsWrapperRelay * node);
SedsResult seds_wrapper_relay_announce_leave(SedsWrapperRelay * node);
SedsResult seds_wrapper_relay_poll_discovery(SedsWrapperRelay * node, bool * out_did_queue);
SedsResult seds_global_relay_process(uint32_t timeout_ms);
SedsResult seds_global_relay_periodic(uint32_t timeout_ms);
SedsResult seds_global_relay_announce_discovery(void);
SedsResult seds_global_relay_announce_leave(void);
SedsResult seds_global_relay_poll_discovery(bool * out_did_queue);
int32_t seds_global_relay_export_topology_len(void);
SedsResult seds_global_relay_export_topology(char * buf, size_t buf_len);
int32_t seds_global_relay_export_client_stats_len(SedsName sender);
SedsResult seds_global_relay_export_client_stats(SedsName sender, char * buf, size_t buf_len);
int32_t seds_global_relay_export_runtime_stats_len(void);
SedsResult seds_global_relay_export_runtime_stats(char * buf, size_t buf_len);
int32_t seds_global_relay_export_memory_layout_len(void);
SedsResult seds_global_relay_export_memory_layout(char * buf, size_t buf_len);

SedsResult seds_global_relay_remove_side(SedsSideRef side);
SedsResult seds_global_relay_set_side_ingress_enabled(SedsSideRef side, bool enabled);
SedsResult seds_global_relay_set_side_egress_enabled(SedsSideRef side, bool enabled);
SedsResult seds_global_relay_set_route(SedsSideRef src_side, SedsSideRef dst_side, bool enabled);
SedsResult seds_global_relay_clear_route(SedsSideRef src_side, SedsSideRef dst_side);
SedsResult seds_global_relay_set_typed_route(SedsSideRef src_side, SedsTypeRef ty, SedsSideRef dst_side, bool enabled);
SedsResult seds_global_relay_clear_typed_route(SedsSideRef src_side, SedsTypeRef ty, SedsSideRef dst_side);
SedsResult seds_global_relay_set_source_route_mode(SedsSideRef src_side, SedsRouteSelectionMode mode);
SedsResult seds_global_relay_clear_source_route_mode(SedsSideRef src_side);
SedsResult seds_global_relay_set_route_weight(SedsSideRef src_side, SedsSideRef dst_side, uint32_t weight);
SedsResult seds_global_relay_clear_route_weight(SedsSideRef src_side, SedsSideRef dst_side);
SedsResult seds_global_relay_set_route_priority(SedsSideRef src_side, SedsSideRef dst_side, uint32_t priority);
SedsResult seds_global_relay_clear_route_priority(SedsSideRef src_side, SedsSideRef dst_side);

static inline SedsResult seds_type_ref_by_name(SedsName name, SedsTypeRef * out)
{
    SedsDataTypeInfo info;
    SedsResult result;
    if (!out) {
        return SEDS_BAD_ARG;
    }
    result = seds_dtype_get_info_by_name(name.ptr, name.len, NULL, 0U, &info);
    if (result != SEDS_OK || !info.exists) {
        return result != SEDS_OK ? result : SEDS_INVALID_TYPE;
    }
    out->id = (SedsDataType)info.id;
    return SEDS_OK;
}

static inline SedsResult seds_endpoint_ref_by_name(SedsName name, SedsEndpointRef * out)
{
    SedsEndpointInfo info;
    SedsResult result;
    if (!out) {
        return SEDS_BAD_ARG;
    }
    result = seds_endpoint_get_info_by_name(name.ptr, name.len, &info);
    if (result != SEDS_OK || !info.exists) {
        return result != SEDS_OK ? result : SEDS_BAD_ARG;
    }
    out->id = (SedsDataEndpoint)info.id;
    return SEDS_OK;
}

static inline bool seds_type_ref_exists(SedsTypeRef ty)
{
    return seds_dtype_exists((uint32_t)ty.id);
}

static inline bool seds_endpoint_ref_exists(SedsEndpointRef endpoint)
{
    return seds_endpoint_exists((uint32_t)endpoint.id);
}

static inline int32_t seds_type_ref_expected_size(SedsTypeRef ty)
{
    return seds_dtype_expected_size(ty.id);
}

#if !defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L

#define SEDS__KIND_SIZE(x, KIND_OUT, SIZE_OUT) do {                                    \
    _Static_assert(sizeof(*(x))==1 || sizeof(*(x))==2 ||                                \
                   sizeof(*(x))==4 || sizeof(*(x))==8,                                  \
                   "element size must be 1,2,4,8");                                     \
    (SIZE_OUT) = (size_t)sizeof(*(x));                                                  \
    (KIND_OUT) = _Generic(*(x),                                                         \
        unsigned char: SEDS_EK_UNSIGNED,                                                \
        uint16_t:      SEDS_EK_UNSIGNED,                                                \
        uint32_t:      SEDS_EK_UNSIGNED,                                                \
        uint64_t:      SEDS_EK_UNSIGNED,                                                \
        signed char:   SEDS_EK_SIGNED,                                                  \
        int16_t:       SEDS_EK_SIGNED,                                                  \
        int32_t:       SEDS_EK_SIGNED,                                                  \
        int64_t:       SEDS_EK_SIGNED,                                                  \
        float:         SEDS_EK_FLOAT,                                                   \
        double:        SEDS_EK_FLOAT,                                                   \
        default:       SEDS_EK_UNSIGNED                                                 \
    );                                                                                  \
} while(0)

#define seds_router_log(router, datatype, data, count)                                  \
    (__extension__({                                                                    \
        const void   *_s_data  = (const void*)(data);                                   \
        size_t        _s_count = (size_t)(count);                                       \
        size_t        _s_esize;                                                         \
        SedsElemKind  _s_kind;                                                          \
        SEDS__KIND_SIZE((data), _s_kind, _s_esize);                                     \
        seds_router_log_typed_ex((router), (datatype), _s_data, _s_count,               \
                                 _s_esize, _s_kind, NULL, 0);                           \
    }))

#define seds_router_log_queue(router, datatype, data, count)                            \
    (__extension__({                                                                    \
        const void   *_s_data  = (const void*)(data);                                   \
        size_t        _s_count = (size_t)(count);                                       \
        size_t        _s_esize;                                                         \
        SedsElemKind  _s_kind;                                                          \
        SEDS__KIND_SIZE((data), _s_kind, _s_esize);                                     \
        seds_router_log_typed_ex((router), (datatype), _s_data, _s_count,               \
                                 _s_esize, _s_kind, NULL, 1);                           \
    }))

#define seds_router_log_ts(router, datatype, ts_ms, data, count)                        \
    (__extension__({                                                                    \
        const void   *_s_data  = (const void*)(data);                                   \
        size_t        _s_count = (size_t)(count);                                       \
        size_t        _s_esize;                                                         \
        SedsElemKind  _s_kind;                                                          \
        const uint64_t _s_ts = (uint64_t)(ts_ms);                                       \
        SEDS__KIND_SIZE((data), _s_kind, _s_esize);                                     \
        seds_router_log_typed_ex((router), (datatype), _s_data, _s_count,               \
                                 _s_esize, _s_kind, &_s_ts, 0);                         \
    }))

#define seds_router_log_queue_ts(router, datatype, ts_ms, data, count)                  \
    (__extension__({                                                                    \
        const void   *_s_data  = (const void*)(data);                                   \
        size_t        _s_count = (size_t)(count);                                       \
        size_t        _s_esize;                                                         \
        SedsElemKind  _s_kind;                                                          \
        const uint64_t _s_ts = (uint64_t)(ts_ms);                                       \
        SEDS__KIND_SIZE((data), _s_kind, _s_esize);                                     \
        seds_router_log_typed_ex((router), (datatype), _s_data, _s_count,               \
                                 _s_esize, _s_kind, &_s_ts, 1);                         \
    }))

#define seds_router_log_cstr(router, datatype, cstr)                                    \
    (__extension__({                                                                    \
        const char *_s = (const char*)(cstr);                                           \
        seds_router_log_string_ex((router), (datatype), _s, (_s?strlen(_s):0), NULL, 0);\
    }))

#define seds_router_log_cstr_queue(router, datatype, cstr)                              \
    (__extension__({                                                                    \
        const char *_s = (const char*)(cstr);                                           \
        seds_router_log_string_ex((router), (datatype), _s, (_s?strlen(_s):0), NULL, 1);\
    }))

#define seds_router_log_cstr_ts(router, datatype, ts_ms, cstr)                          \
    (__extension__({                                                                    \
        const char *_s = (const char*)(cstr);                                           \
        const uint64_t _s_ts = (uint64_t)(ts_ms);                                       \
        seds_router_log_string_ex((router), (datatype), _s, (_s?strlen(_s):0), &_s_ts, 0);\
    }))

#define seds_router_log_cstr_queue_ts(router, datatype, ts_ms, cstr)                    \
    (__extension__({                                                                    \
        const char *_s = (const char*)(cstr);                                           \
        const uint64_t _s_ts = (uint64_t)(ts_ms);                                       \
        seds_router_log_string_ex((router), (datatype), _s, (_s?strlen(_s):0), &_s_ts, 1);\
    }))

#define seds_pkt_get(pkt, out, count)                                                   \
    (__extension__({                                                                    \
        void        *_s_out   = (void*)(out);                                           \
        size_t       _s_count = (size_t)(count);                                        \
        size_t       _s_esize;                                                          \
        SedsElemKind _s_kind;                                                           \
        SEDS__KIND_SIZE((out), _s_kind, _s_esize);                                      \
        seds_pkt_get_typed((pkt), _s_out, _s_count, _s_esize, _s_kind);                 \
    }))
#endif

#ifdef __cplusplus
}
#endif

#endif