Skip to content

Commit

Permalink
Draft attachment support implementation
Browse files Browse the repository at this point in the history
Based on eclipse-zenoh#190 with minor
changes:
 - attachement(s) -> attachment renaming
 - conflicts resolving
 - formatting
  • Loading branch information
sashacmc committed Dec 4, 2023
1 parent 108c20e commit d13137d
Show file tree
Hide file tree
Showing 9 changed files with 527 additions and 4 deletions.
5 changes: 5 additions & 0 deletions examples/z_put.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ int main(int argc, char **argv) {
if (argc > 1) keyexpr = argv[1];
if (argc > 2) value = argv[2];

z_owned_bytes_map_t attachment = z_bytes_map_new();
z_bytes_map_insert_by_copy(&attachment, z_bytes_new("hello"), z_bytes_new("there"));

z_owned_config_t config = z_config_default();
if (argc > 3) {
if (zc_config_insert_json(z_loan(config), Z_CONFIG_CONNECT_KEY, argv[3]) < 0) {
Expand All @@ -44,11 +47,13 @@ int main(int argc, char **argv) {
printf("Putting Data ('%s': '%s')...\n", keyexpr, value);
z_put_options_t options = z_put_options_default();
options.encoding = z_encoding(Z_ENCODING_PREFIX_TEXT_PLAIN, NULL);
options.attachment = z_bytes_map_as_attachment(&attachment);
int res = z_put(z_loan(s), z_keyexpr(keyexpr), (const uint8_t *)value, strlen(value), &options);
if (res < 0) {
printf("Put failed...\n");
}

z_close(z_move(s));
z_drop(z_move(attachment));
return 0;
}
7 changes: 6 additions & 1 deletion examples/z_sub.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// Contributors:
// ZettaScale Zenoh Team, <[email protected]>
//
#include <stdint.h>
#include <stdio.h>
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#include <windows.h>
Expand All @@ -26,6 +27,10 @@ void data_handler(const z_sample_t *sample, void *arg) {
z_owned_str_t keystr = z_keyexpr_to_string(sample->keyexpr);
printf(">> [Subscriber] Received %s ('%s': '%.*s')\n", kind_to_str(sample->kind), z_loan(keystr),
(int)sample->payload.len, sample->payload.start);
if (z_check(sample->attachment)) {
z_owned_bytes_map_t map = z_bytes_map_from_attachment(sample->attachment);
z_bytes_t there = z_bytes_map_get(&map, z_bytes_new("hello"));
}
z_drop(z_move(keystr));
}

Expand Down Expand Up @@ -91,4 +96,4 @@ const char *kind_to_str(z_sample_kind_t kind) {
default:
return "UNKNOWN";
}
}
}
173 changes: 172 additions & 1 deletion include/zenoh_commons.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,68 @@ typedef enum zcu_reply_keyexpr_t {
ZCU_REPLY_KEYEXPR_MATCHING_QUERY = 1,
} zcu_reply_keyexpr_t;
/**
* An array of bytes.
* A contiguous view of bytes owned by some other entity.
*
* `start` being `null` is considered a gravestone value,
* and empty slices are represented using a possibly dangling pointer for `start`.
*/
typedef struct z_bytes_t {
size_t len;
const uint8_t *start;
} z_bytes_t;
/**
* The body of a loop over an attachment's key-value pairs.
*
* `key` and `value` are loaned to the body for the duration of a single call.
* `context` is passed transparently through the iteration driver.
*
* Returning `0` is treated as `continue`.
* Returning any other value is treated as `break`.
*/
typedef int8_t (*z_attachment_iter_body_t)(struct z_bytes_t key,
struct z_bytes_t value,
void *context);
/**
* The driver of a loop over an attachment's key-value pairs.
*
* This function is expected to call `loop_body` once for each key-value pair
* within `iterator`, passing `context`, and returning any non-zero value immediately (breaking iteration).
*/
typedef int8_t (*z_attachment_iter_driver_t)(void *iterator,
z_attachment_iter_body_t loop_body,
void *context);
/**
* The v-table for an attachment.
*/
typedef struct z_attachment_vtable_t {
/**
* See `z_attachment_iteration_driver_t`'s documentation.
*/
z_attachment_iter_driver_t iteration_driver;
/**
* Returns the number of key-value pairs within the attachment.
*/
size_t (*len)(const void*);
} z_attachment_vtable_t;
/**
* A v-table based map of byte slice to byte slice.
*
* `vtable == NULL` marks the gravestone value, as this type is often optional.
* Users are encouraged to use `z_attachment_null` and `z_attachment_check` to interact.
*/
typedef struct z_attachment_t {
void *data;
const struct z_attachment_vtable_t *vtable;
} z_attachment_t;
/**
* A map of maybe-owned vector of bytes to owned vector of bytes.
*
* In Zenoh C, this map is backed by Rust's standard HashMap, with a DoS-resistant hasher
*/
typedef struct z_owned_bytes_map_t {
uint64_t _0[2];
size_t _1[4];
} z_owned_bytes_map_t;
/**
* Represents a Zenoh ID.
*
Expand Down Expand Up @@ -340,6 +396,7 @@ typedef struct z_sample_t {
const void *_zc_buf;
enum z_sample_kind_t kind;
struct z_timestamp_t timestamp;
struct z_attachment_t attachment;
} z_sample_t;
/**
* A closure is a structure that contains all the elements for stateful, memory-leak-free callbacks.
Expand Down Expand Up @@ -629,6 +686,7 @@ typedef struct z_put_options_t {
struct z_encoding_t encoding;
enum z_congestion_control_t congestion_control;
enum z_priority_t priority;
struct z_attachment_t attachment;
} z_put_options_t;
/**
* Represents the set of options that can be applied to a query reply,
Expand Down Expand Up @@ -812,10 +870,123 @@ ZENOHC_API extern const char *Z_CONFIG_MULTICAST_IPV4_ADDRESS_KEY;
ZENOHC_API extern const char *Z_CONFIG_SCOUTING_TIMEOUT_KEY;
ZENOHC_API extern const char *Z_CONFIG_SCOUTING_DELAY_KEY;
ZENOHC_API extern const char *Z_CONFIG_ADD_TIMESTAMP_KEY;
/**
* Returns the gravestone value for `z_attachment_t`.
*/
ZENOHC_API bool z_attachment_check(const struct z_attachment_t *this_);
/**
* Iterate over `this`'s key-value pairs, breaking if `body` returns a non-zero
* value for a key-value pair, and returning the latest return value.
*
* `context` is passed to `body` to allow stateful closures.
*
* This function takes no ownership whatsoever.
*/
ZENOHC_API
int8_t z_attachment_iterate(struct z_attachment_t this_,
z_attachment_iter_body_t body,
void *context);
/**
* Returns the number of key-value pairs in `this`.
*/
ZENOHC_API size_t z_attachment_len(struct z_attachment_t this_);
/**
* Returns the gravestone value for `z_attachment_t`.
*/
ZENOHC_API struct z_attachment_t z_attachment_null(void);
/**
* Returns ``true`` if `b` is initialized.
*/
ZENOHC_API bool z_bytes_check(const struct z_bytes_t *b);
/**
* Aliases `this` into a generic `z_attachment_t`, allowing it to be passed to corresponding APIs.
*/
ZENOHC_API struct z_attachment_t z_bytes_map_as_attachment(const struct z_owned_bytes_map_t *this_);
/**
* Returns `true` if the map is not in its gravestone state
*/
ZENOHC_API bool z_bytes_map_check(const struct z_owned_bytes_map_t *this_);
/**
* Destroys the map, resetting `this` to its gravestone value.
*
* This function is double-free safe, passing a pointer to the gravestone value will have no effect.
*/
ZENOHC_API void z_bytes_map_drop(struct z_owned_bytes_map_t *this_);
/**
* Constructs a map from the provided attachment, copying keys and values.
*
* If `this` is at gravestone value, the returned value will also be at gravestone value.
*/
ZENOHC_API struct z_owned_bytes_map_t z_bytes_map_from_attachment(struct z_attachment_t this_);
/**
* Constructs a map from the provided attachment, aliasing the attachment's keys and values.
*
* If `this` is at gravestone value, the returned value will also be at gravestone value.
*/
ZENOHC_API
struct z_owned_bytes_map_t z_bytes_map_from_attachment_aliasing(struct z_attachment_t this_);
/**
* Returns the value associated with `key`, returning a gravestone value if:
* - `this` or `key` is in gravestone state.
* - `this` has no value associated to `key`
*/
ZENOHC_API
struct z_bytes_t z_bytes_map_get(const struct z_owned_bytes_map_t *this_,
struct z_bytes_t key);
/**
* Associates `value` to `key` in the map, aliasing them.
*
* Note that once `key` is aliased, reinserting at the same key may alias the previous instance, or the new instance of `key`.
*
* Calling this with `NULL` or the gravestone value is undefined behaviour.
*/
ZENOHC_API
void z_bytes_map_insert_by_alias(const struct z_owned_bytes_map_t *this_,
struct z_bytes_t key,
struct z_bytes_t value);
/**
* Associates `value` to `key` in the map, copying them to obtain ownership: `key` and `value` are not aliased past the function's return.
*
* Calling this with `NULL` or the gravestone value is undefined behaviour.
*/
ZENOHC_API
void z_bytes_map_insert_by_copy(const struct z_owned_bytes_map_t *this_,
struct z_bytes_t key,
struct z_bytes_t value);
/**
* Iterates over the key-value pairs in the map.
*
* `body` will be called once per pair, with `ctx` as its last argument.
* If `body` returns a non-zero value, the iteration will stop immediately and the value will be returned.
* Otherwise, this will return 0 once all pairs have been visited.
* `body` is not given ownership of the key nor value, which alias the pairs in the map.
* It is safe to keep these aliases until existing keys are modified/removed, or the map is destroyed.
* Note that this map is unordered.
*
* Calling this with `NULL` or the gravestone value is undefined behaviour.
*/
ZENOHC_API
int8_t z_bytes_map_iter(const struct z_owned_bytes_map_t *this_,
z_attachment_iter_body_t body,
void *ctx);
/**
* Constructs a new map.
*/
ZENOHC_API struct z_owned_bytes_map_t z_bytes_map_new(void);
/**
* Constructs the gravestone value for `z_owned_bytes_map_t`
*/
ZENOHC_API struct z_owned_bytes_map_t z_bytes_map_null(void);
/**
* Returns a view of `str` using `strlen`.
*
* `str == NULL` will cause this to return `z_bytes_null()`
*/
ZENOHC_API struct z_bytes_t z_bytes_new(const char *str);
/**
* Returns the gravestone value for `z_bytes_t`
*/
ZENOHC_API struct z_bytes_t z_bytes_null(void);
/**
* Closes a zenoh session. This drops and invalidates `session` for double-drop safety.
*
Expand Down
6 changes: 6 additions & 0 deletions include/zenoh_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
z_owned_closure_zid_t * : z_closure_zid_drop, \
z_owned_reply_channel_closure_t * : z_reply_channel_closure_drop, \
z_owned_reply_channel_t * : z_reply_channel_drop, \
z_owned_bytes_map_t * : z_bytes_map_drop, \
zc_owned_payload_t * : zc_payload_drop, \
zc_owned_shmbuf_t * : zc_shmbuf_drop, \
zc_owned_shm_manager_t * : zc_shm_manager_drop, \
Expand All @@ -44,6 +45,8 @@
ze_owned_querying_subscriber_t * : ze_undeclare_querying_subscriber \
)(x)

// TODO(sashacmc): Check z_attachment_t name

#define z_null(x) (*x = \
_Generic((x), z_owned_session_t * : z_session_null, \
z_owned_publisher_t * : z_publisher_null, \
Expand All @@ -64,6 +67,7 @@
z_owned_closure_zid_t * : z_closure_zid_null, \
z_owned_reply_channel_closure_t * : z_reply_channel_closure_null, \
z_owned_reply_channel_t * : z_reply_channel_null, \
z_attachment_t : z_attachment_null, \
zc_owned_payload_t * : zc_payload_null, \
zc_owned_shmbuf_t * : zc_shmbuf_null, \
zc_owned_shm_manager_t * : zc_shm_manager_null, \
Expand All @@ -86,6 +90,8 @@
z_owned_reply_t : z_reply_check, \
z_owned_hello_t : z_hello_check, \
z_owned_str_t : z_str_check, \
z_attachment_t : z_attachment_check, \
z_owned_bytes_map_t : z_bytes_map_check, \
zc_owned_payload_t : zc_payload_check, \
zc_owned_shmbuf_t : zc_shmbuf_check, \
zc_owned_shm_manager_t : zc_shm_manager_check, \
Expand Down
Loading

0 comments on commit d13137d

Please sign in to comment.