Skip to content

Commit

Permalink
attachment API implemented, todo: integration with options and codecs
Browse files Browse the repository at this point in the history
  • Loading branch information
p-avital committed Dec 13, 2023
1 parent 20d8351 commit 6b710b0
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 5 deletions.
6 changes: 3 additions & 3 deletions include/zenoh-pico/api/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// ZettaScale Zenoh Team, <[email protected]>
//

#ifndef ZENOH_PICO_API_PRIMITIVES_H
#define ZENOH_PICO_API_PRIMITIVES_H
#ifndef INCLUDE_ZENOH_PICO_API_PRIMITIVES_H
#define INCLUDE_ZENOH_PICO_API_PRIMITIVES_H

#include <stdbool.h>
#include <stdint.h>
Expand Down Expand Up @@ -1400,4 +1400,4 @@ int8_t zp_send_join(z_session_t zs, const zp_send_join_options_t *options);
}
#endif

#endif /* ZENOH_PICO_API_PRIMITIVES_H */
#endif /* INCLUDE_ZENOH_PICO_API_PRIMITIVES_H */
108 changes: 108 additions & 0 deletions include/zenoh-pico/api/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#ifndef INCLUDE_ZENOH_PICO_API_TYPES_H
#define INCLUDE_ZENOH_PICO_API_TYPES_H

#include "zenoh-pico/collections/bytes.h"
#include "zenoh-pico/collections/element.h"
#include "zenoh-pico/collections/list.h"
#include "zenoh-pico/net/publish.h"
#include "zenoh-pico/net/query.h"
#include "zenoh-pico/net/session.h"
Expand Down Expand Up @@ -289,6 +292,7 @@ typedef struct {
z_encoding_t encoding;
z_congestion_control_t congestion_control;
z_priority_t priority;
z_attachment_t attachment;
} z_put_options_t;

/**
Expand All @@ -313,6 +317,7 @@ typedef struct {
*/
typedef struct {
z_encoding_t encoding;
z_attachment_t attachment;
} z_publisher_put_options_t;

/**
Expand All @@ -336,6 +341,7 @@ typedef struct {
z_value_t value;
z_query_consolidation_t consolidation;
z_query_target_t target;
z_attachment_t attachment;
} z_get_options_t;

/**
Expand Down Expand Up @@ -546,6 +552,108 @@ typedef struct {

void z_closure_zid_call(const z_owned_closure_zid_t *closure, const z_id_t *id);

struct _z_bytes_pair_t {
_z_bytes_t key;
_z_bytes_t value;
};

void _z_bytes_pair_clear(struct _z_bytes_pair_t *this);

_Z_ELEM_DEFINE(_z_bytes_pair, struct _z_bytes_pair_t, _z_noop_size, _z_bytes_pair_clear, _z_noop_copy);
_Z_LIST_DEFINE(_z_bytes_pair, struct _z_bytes_pair_t);

/**
* A map of maybe-owned vector of bytes to maybe-owned vector of bytes.
*/
typedef struct z_owned_bytes_map_t {
_z_bytes_pair_list_t *_inner;
} z_owned_bytes_map_t;

/**
* Aliases `this` into a generic `z_attachment_t`, allowing it to be passed to corresponding APIs.
*/
z_attachment_t z_bytes_map_as_attachment(const z_owned_bytes_map_t *this_);
/**
* Returns `true` if the map is not in its gravestone state
*/
bool z_bytes_map_check(const 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.
*/
void z_bytes_map_drop(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.
*/
z_owned_bytes_map_t z_bytes_map_from_attachment(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.
*/

z_owned_bytes_map_t z_bytes_map_from_attachment_aliasing(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`
*/

z_bytes_t z_bytes_map_get(const z_owned_bytes_map_t *this_, 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.
*/

void z_bytes_map_insert_by_alias(const z_owned_bytes_map_t *this_, z_bytes_t key, 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.
*/

void z_bytes_map_insert_by_copy(const z_owned_bytes_map_t *this_, z_bytes_t key, 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.
*/

int8_t z_bytes_map_iter(const z_owned_bytes_map_t *this_, z_attachment_iter_body_t body, void *ctx);
/**
* Constructs a new map.
*/
z_owned_bytes_map_t z_bytes_map_new(void);
/**
* Constructs the gravestone value for `z_owned_bytes_map_t`
*/
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()`
*/
z_bytes_t z_bytes_new(const char *str);
/**
* Returns the gravestone value for `z_bytes_t`
*/
z_bytes_t z_bytes_null(void);

#ifdef __cplusplus
}
#endif
Expand Down
46 changes: 46 additions & 0 deletions include/zenoh-pico/protocol/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define INCLUDE_ZENOH_PICO_PROTOCOL_CORE_H

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

Expand Down Expand Up @@ -71,6 +72,50 @@ typedef struct {
uint64_t time;
} _z_timestamp_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)(_z_bytes_t key, _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)(const 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;
} 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 {
const void *data;
z_attachment_iter_driver_t iteration_driver;
} z_attachment_t;

inline z_attachment_t z_attachment_null() { return (z_attachment_t){.data = NULL, .iteration_driver = NULL}; }
inline _Bool z_attachment_check(const z_attachment_t *attachment) { return attachment->iteration_driver != NULL; }
inline int8_t z_attachment_iterate(z_attachment_t this, z_attachment_iter_body_t body, void *ctx) {
return this.iteration_driver(this.data, body, ctx);
}
_z_bytes_t z_attachment_get(z_attachment_t this, _z_bytes_t key);

_z_timestamp_t _z_timestamp_duplicate(const _z_timestamp_t *tstamp);
_z_timestamp_t _z_timestamp_null(void);
void _z_timestamp_clear(_z_timestamp_t *tstamp);
Expand Down Expand Up @@ -168,6 +213,7 @@ typedef struct {
_z_timestamp_t timestamp;
_z_encoding_t encoding;
z_sample_kind_t kind;
z_attachment_t attachment;
} _z_sample_t;

/**
Expand Down
114 changes: 113 additions & 1 deletion src/api/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1090,4 +1090,116 @@ zp_send_join_options_t zp_send_join_options_default(void) { return (zp_send_join
int8_t zp_send_join(z_session_t zs, const zp_send_join_options_t *options) {
(void)(options);
return _zp_send_join(zs._val);
}
}

void _z_bytes_pair_clear(struct _z_bytes_pair_t *this) {
_z_bytes_clear(&this->key);
_z_bytes_clear(&this->value);
}

z_attachment_t z_bytes_map_as_attachment(const z_owned_bytes_map_t *this_) {
if (!z_bytes_map_check(this_)) {
return z_attachment_null();
}
return (z_attachment_t){.data = this_, .iteration_driver = (z_attachment_iter_driver_t)z_bytes_map_iter};
}
bool z_bytes_map_check(const z_owned_bytes_map_t *this_) { return this_->_inner != NULL; }
void z_bytes_map_drop(z_owned_bytes_map_t *this_) { _z_bytes_pair_list_free(&this_->_inner); }

int8_t _z_bytes_map_insert_by_alias(z_bytes_t key, z_bytes_t value, void *this_) {
z_bytes_map_insert_by_alias((z_owned_bytes_map_t *)this_, key, value);
return 0;
}
int8_t _z_bytes_map_insert_by_copy(z_bytes_t key, z_bytes_t value, void *this_) {
z_bytes_map_insert_by_copy((z_owned_bytes_map_t *)this_, key, value);
return 0;
}
z_owned_bytes_map_t z_bytes_map_from_attachment(z_attachment_t this_) {
if (!z_attachment_check(&this_)) {
return z_bytes_map_null();
}
z_owned_bytes_map_t map = z_bytes_map_new();
z_attachment_iterate(this_, _z_bytes_map_insert_by_copy, &map);
return map;
}
z_owned_bytes_map_t z_bytes_map_from_attachment_aliasing(z_attachment_t this_) {
if (!z_attachment_check(&this_)) {
return z_bytes_map_null();
}
z_owned_bytes_map_t map = z_bytes_map_new();
z_attachment_iterate(this_, _z_bytes_map_insert_by_alias, &map);
return map;
}
z_bytes_t z_bytes_map_get(const z_owned_bytes_map_t *this_, z_bytes_t key) {
_z_bytes_pair_list_t *current = this_->_inner;
while (current) {
struct _z_bytes_pair_t *head = _z_bytes_pair_list_head(current);
if (_z_bytes_eq(&key, &head->key)) {
return _z_bytes_wrap(head->value.start, head->value.len);
}
}
return z_bytes_null();
}
void z_bytes_map_insert_by_alias(const z_owned_bytes_map_t *this_, z_bytes_t key, z_bytes_t value) {
_z_bytes_pair_list_t *current = this_->_inner;
while (current) {
struct _z_bytes_pair_t *head = _z_bytes_pair_list_head(current);
if (_z_bytes_eq(&key, &head->key)) {
break;
}
current = _z_bytes_pair_list_tail(current);
}
if (current) {
struct _z_bytes_pair_t *head = _z_bytes_pair_list_head(current);
_z_bytes_clear(&head->value);
head->value = _z_bytes_wrap(value.start, value.len);
} else {
struct _z_bytes_pair_t *insert = z_malloc(sizeof(struct _z_bytes_pair_t));
memset(insert, 0, sizeof(struct _z_bytes_pair_t));
insert->key = _z_bytes_wrap(key.start, key.len);
insert->value = _z_bytes_wrap(value.start, value.len);
_z_bytes_pair_list_push(this_->_inner, insert);
}
}
void z_bytes_map_insert_by_copy(const z_owned_bytes_map_t *this_, z_bytes_t key, z_bytes_t value) {
_z_bytes_pair_list_t *current = this_->_inner;
while (current) {
struct _z_bytes_pair_t *head = _z_bytes_pair_list_head(current);
if (_z_bytes_eq(&key, &head->key)) {
break;
}
current = _z_bytes_pair_list_tail(current);
}
if (current) {
struct _z_bytes_pair_t *head = _z_bytes_pair_list_head(current);
_z_bytes_clear(&head->value);
_z_bytes_copy(&head->value, &value);
if (!head->key._is_alloc) {
_z_bytes_copy(&head->key, &key);
}
} else {
struct _z_bytes_pair_t *insert = z_malloc(sizeof(struct _z_bytes_pair_t));
memset(insert, 0, sizeof(struct _z_bytes_pair_t));
_z_bytes_copy(&insert->key, &key);
_z_bytes_copy(&insert->value, &value);
_z_bytes_pair_list_push(this_->_inner, insert);
}
}
int8_t z_bytes_map_iter(const z_owned_bytes_map_t *this_, z_attachment_iter_body_t body, void *ctx) {
_z_bytes_pair_list_t *current = this_->_inner;
while (current) {
struct _z_bytes_pair_t *head = _z_bytes_pair_list_head(current);
int8_t ret = body(head->key, head->value, ctx);
if (ret) {
return ret;
}
current = _z_bytes_pair_list_tail(current);
}
return 0;
}
z_owned_bytes_map_t z_bytes_map_new(void) { return (z_owned_bytes_map_t){._inner = _z_bytes_pair_list_new()}; }
z_owned_bytes_map_t z_bytes_map_null(void) { return (z_owned_bytes_map_t){._inner = NULL}; }
z_bytes_t z_bytes_new(const char *str) {
return (z_bytes_t){.len = strlen(str), ._is_alloc = false, .start = (unsigned char *)str};
}
z_bytes_t z_bytes_null(void) { return (z_bytes_t){.len = 0, ._is_alloc = false, .start = NULL}; }
22 changes: 22 additions & 0 deletions src/protocol/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

#include "zenoh-pico/protocol/core.h"

#include <stdint.h>
#include <string.h>

#include "zenoh-pico/api/primitives.h"
#include "zenoh-pico/collections/bytes.h"

uint8_t _z_id_len(_z_id_t id) {
uint8_t len = 16;
Expand Down Expand Up @@ -64,3 +68,21 @@ _z_value_t _z_value_steal(_z_value_t *value) {
*value = _z_value_null();
return ret;
}
struct _z_seeker_t {
_z_bytes_t key;
_z_bytes_t value;
};
int8_t _z_attachment_get_seeker(_z_bytes_t key, _z_bytes_t value, void *ctx) {
struct _z_seeker_t *seeker = (struct _z_seeker_t *)ctx;
_z_bytes_t seeked = seeker->key;
if (key.len == seeked.len && memcmp(key.start, seeked.start, seeked.len)) {
seeker->value = (_z_bytes_t){.start = value.start, .len = value.len, ._is_alloc = false};
return 1;
}
return 0;
}
_z_bytes_t z_attachment_get(z_attachment_t this, _z_bytes_t key) {
struct _z_seeker_t seeker = {.value = {0}, .key = key};
z_attachment_iterate(this, _z_attachment_get_seeker, (void *)&seeker);
return seeker.value;
}
2 changes: 1 addition & 1 deletion zenohpico.pc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ prefix=/usr/local
Name: zenohpico
Description:
URL:
Version: 0.11.20231031dev
Version: 0.11.20231213dev
Cflags: -I${prefix}/include
Libs: -L${prefix}/lib -lzenohpico

0 comments on commit 6b710b0

Please sign in to comment.