diff --git a/README.md b/README.md index ff79b1398..639070122 100644 --- a/README.md +++ b/README.md @@ -144,35 +144,7 @@ cmake ../zenoh-c/examples -DCMAKE_INSTALL_PREFIX=~/.local ## Running the Examples -### Basic Pub/Sub Example - -```bash -./target/release/examples/z_sub -``` - -```bash -./target/release/examples/z_pub -``` - -### Queryable and Query Example - -```bash -./target/release/examples/z_queryable -``` - -```bash -./target/release/examples/z_get -``` - -### Running the Throughput Examples - -```bash -./target/release/examples/z_sub_thr -``` - -```bash -./target/release/examples/z_pub_thr -``` +See [readme](./examples/README.md) ## Documentation diff --git a/build-resources/opaque-types/src/lib.rs b/build-resources/opaque-types/src/lib.rs index d14c0719d..d25d84c93 100644 --- a/build-resources/opaque-types/src/lib.rs +++ b/build-resources/opaque-types/src/lib.rs @@ -50,11 +50,11 @@ macro_rules! get_opaque_type_data { }; } -/// A serialized Zenoh data. +/// A Zenoh data. /// /// To minimize copies and reallocations, Zenoh may provide data in several separate buffers. get_opaque_type_data!(ZBytes, z_owned_bytes_t); -/// A loaned serialized Zenoh data. +/// A loaned Zenoh data. get_opaque_type_data!(ZBytes, z_loaned_bytes_t); pub struct CSlice { diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..90904e93c --- /dev/null +++ b/examples/README.md @@ -0,0 +1,319 @@ +# Zenoh C examples + +## Start instructions + + When Zenoh is built in release mode: + + ```bash + ./target/release/example/ + ``` + + Each example accepts the `-h` or `--help` option that provides a description of its arguments and their default values. + + If you run the tests against the Zenoh router running in a Docker container, you need to add the + `-e tcp/localhost:7447` option to your examples. That's because Docker doesn't support UDP multicast + transport, and therefore the Zenoh scouting and discovery mechanism cannot work with. + +## Examples description + +### z_scout + + Scouts for Zenoh peers and routers available on the network. + + Typical usage: + + ```bash + z_scout + ``` + +### z_info + + Gets information about the Zenoh session. + + Typical usage: + + ```bash + z_info + ``` + +### z_put + + Puts a path/value into Zenoh. + The path/value will be received by all matching subscribers, for instance the [z_sub](#z_sub) + and [z_storage](#z_storage) examples. + + Typical usage: + + ```bash + z_put + ``` + + or + + ```bash + z_put -k demo/example/test -v 'Hello World' + ``` + +### z_pub + + Declares a key expression and a publisher. Then writes values periodically on the declared key expression. + The published value will be received by all matching subscribers, for instance the [z_sub](#z_sub) and [z_storage](#z_storage) examples. + + Typical usage: + + ```bash + z_pub + ``` + + or + + ```bash + z_pub -k demo/example/test -v 'Hello World' + ``` + +### z_sub + + Declares a key expression and a subscriber. + The subscriber will be notified of each `put` or `delete` made on any key expression matching the subscriber key expression, and will print this notification. + + Typical usage: + + ```bash + z_sub + ``` + + or + + ```bash + z_sub -k 'demo/**' + ``` + +### z_pull + + Declares a key expression and a pull subscriber. + On each pull, the pull subscriber will be notified of the last N `put` or `delete` made on each key expression matching the subscriber key expression, and will print this notification. + + Typical usage: + + ```bash + z_pull + ``` + + or + + ```bash + z_pull -k demo/** --size 3 + ``` + +### z_get + + Sends a query message for a selector. + The queryables with a matching path or selector (for instance [z_queryable](#z_queryable) and [z_storage](#z_storage)) + will receive this query and reply with paths/values that will be received by the receiver stream. + + Typical usage: + + ```bash + z_get + ``` + + or + + ```bash + z_get -s 'demo/**' + ``` + +### z_querier + + Continuously sends query messages for a selector. + The queryables with a matching path or selector (for instance [z_queryable](#z_queryable) and [z_storage](#z_storage)) + will receive these queries and reply with paths/values that will be received by the querier. + + Typical usage: + + ```bash + z_querier + ``` + + or + + ```bash + z_querier -s 'demo/**' + ``` + +### z_queryable + + Declares a queryable function with a path. + This queryable function will be triggered by each call to get + with a selector that matches the path, and will return a value to the querier. + + Typical usage: + + ```bash + z_queryable + ``` + + or + + ```bash + z_queryable -k demo/example/queryable -v 'This is the result' + ``` + +### z_storage + + Trivial implementation of a storage in memory. + This example declares a subscriber and a queryable on the same selector. + The subscriber callback will store the received paths/values in a hashmap. + The queryable callback will answer to queries with the paths/values stored in the hashmap + and that match the queried selector. + + Typical usage: + + ```bash + z_storage + ``` + + or + + ```bash + z_storage -k 'demo/**' + ``` + +### z_pub_shm & z_sub + + A pub/sub example involving the shared-memory feature. + Note that on subscriber side, the same `z_sub` example than for non-shared-memory example is used. + + Typical Subscriber usage: + + ```bash + z_sub + ``` + + Typical Publisher usage: + + ```bash + z_pub_shm + ``` + +### z_pub_thr & z_sub_thr + + Pub/Sub throughput test. + This example allows performing throughput measurements between a publisher performing + put operations and a subscriber receiving notifications of those puts. + + Typical Subscriber usage: + + ```bash + z_sub_thr + ``` + + Typical Publisher usage: + + ```bash + z_pub_thr 1024 + ``` + +### z_ping & z_pong + + Pub/Sub roundtrip time test. + This example allows performing roundtrip time measurements. The z_ping example + performs a put operation on a first key expression, waits for a reply from the pong + example on a second key expression and measures the time between the two. + The pong application waits for samples on the first key expression and replies by + writing back the received data on the second key expression. + + :warning: z_pong needs to start first to avoid missing the kickoff from z_ping. + + Typical Pong usage: + + ```bash + z_pong + ``` + + Typical Ping usage: + + ```bash + z_ping 1024 + ``` + +### z_pub_shm_thr & z_sub_thr + + Pub/Sub throughput test involving the shared-memory feature. + This example allows performing throughput measurements between a publisher performing + put operations with the shared-memory feature and a subscriber receiving notifications + of those puts. + Note that on subscriber side, the same `z_sub_thr` example than for non-shared-memory example is used. + + Typical Subscriber usage: + + ```bash + z_sub_thr + ``` + + Typical Publisher usage: + + ```bash + z_pub_shm_thr + ``` + +### z_liveliness + + Declares a liveliness token on a given key expression (`group1/zenoh-rs` by default). + This token will be seen alive by the `z_get_liveliness` and `z_sub_liveliness` until + user explicitly drops the token by pressing `'d'` or implicitly dropped by terminating + or killing the `z_liveliness` example. + + Typical usage: + + ```bash + z_liveliness + ``` + + or + + ```bash + z_liveliness -k 'group1/member1' + ``` + +### z_get_liveliness + + Queries all the currently alive liveliness tokens that match a given key expression + (`group1/**` by default). Those tokens could be declared by the `z_liveliness` example. + + Typical usage: + + ```bash + z_get_liveliness + ``` + + or + + ```bash + z_get_liveliness -k 'group1/**' + ``` + +### z_sub_liveliness + + Subscribe to all liveliness changes (liveliness tokens getting alive or + liveliness tokens being dropped) that match a given key expression + (`group1/**` by default). Those tokens could be declared by the `z_liveliness` + example. + Note: the `z_sub_liveliness` example will not receive information about + matching liveliness tokens that were alive before it's start. + + Typical usage: + + ```bash + z_sub_liveliness + ``` + + or + + ```bash + z_sub_liveliness -k 'group1/**' + ``` + +### z_bytes + + Show how to serialize different message types into ZBytes, and then deserialize from ZBytes to the original message types. diff --git a/examples/z_pub_thr.c b/examples/z_pub_thr.c index 75b1f1f9a..614a45f91 100644 --- a/examples/z_pub_thr.c +++ b/examples/z_pub_thr.c @@ -78,7 +78,7 @@ void print_help() { Arguments:\n\ (required, number): Size of the payload to publish\n\n\ Options:\n\ - -p (optional, number [%d - %d], default='%d'): Priority for sending data\n\ + -p, --priority (optional, number [%d - %d], default='%d'): Priority for sending data\n\ --express (optional): Batch messages.\n", Z_PRIORITY_REAL_TIME, Z_PRIORITY_BACKGROUND, DEFAULT_PRIORITY); printf(COMMON_HELP); diff --git a/examples/z_put.c b/examples/z_put.c index 5758be662..376152266 100644 --- a/examples/z_put.c +++ b/examples/z_put.c @@ -46,19 +46,8 @@ int main(int argc, char** argv) { z_owned_bytes_t payload; z_bytes_from_static_str(&payload, args.value); - z_put_options_t options; - z_put_options_default(&options); - z_owned_bytes_t attachment; - ze_owned_serializer_t serializer; - ze_serializer_empty(&serializer); - ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 1); // 1 key-value pair - ze_serializer_serialize_str(z_loan_mut(serializer), "hello"); - ze_serializer_serialize_str(z_loan_mut(serializer), "there"); - ze_serializer_finish(z_move(serializer), &attachment); - - options.attachment = z_move(attachment); // attachement is consumed by z_put, so no need to drop it manually - int res = z_put(z_loan(s), z_loan(ke), z_move(payload), &options); + int res = z_put(z_loan(s), z_loan(ke), z_move(payload), NULL); if (res < 0) { printf("Put failed...\n"); } diff --git a/examples/z_queryable.c b/examples/z_queryable.c index d0420a63d..f720159ab 100644 --- a/examples/z_queryable.c +++ b/examples/z_queryable.c @@ -114,7 +114,7 @@ void print_help() { Options:\n\ -k, --key (optional, string, default='%s'): The key expression matching queries to reply to\n\ -p, --payload (optional, string, default='%s'): The value to reply to queries with\n\ - --complete (optional, flag to indicate whether queryable is complete or not)", + --complete (optional): Indicates whether queryable is complete or not", DEFAULT_KEYEXPR, DEFAULT_VALUE); printf(COMMON_HELP); } diff --git a/examples/z_scout.c b/examples/z_scout.c index 1013e30a5..875f6a95b 100644 --- a/examples/z_scout.c +++ b/examples/z_scout.c @@ -16,21 +16,10 @@ #include "zenoh.h" void fprintpid(FILE *stream, z_id_t pid) { - int len = 0; - for (int i = 0; i < 16; i++) { - if (pid.id[i]) { - len = i + 1; - } - } - if (!len) { - fprintf(stream, "None"); - } else { - fprintf(stream, "Some("); - for (unsigned int i = 0; i < len; i++) { - fprintf(stream, "%02X", (int)pid.id[i]); - } - fprintf(stream, ")"); - } + z_owned_string_t str; + z_id_to_string(&pid, &str); + fprintf(stream, "%.*s", (int)z_string_len(z_loan(str)), z_string_data(z_loan(str))); + z_drop(z_move(str)); } void fprintwhatami(FILE *stream, z_whatami_t whatami) { @@ -42,10 +31,8 @@ void fprintwhatami(FILE *stream, z_whatami_t whatami) { void fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) { fprintf(stream, "["); for (unsigned int i = 0; i < z_string_array_len(locs); i++) { - fprintf(stream, "\""); const z_loaned_string_t *loc = z_string_array_get(locs, i); fprintf(stream, "%.*s", (int)z_string_len(loc), z_string_data(loc)); - fprintf(stream, "\""); if (i < z_string_array_len(locs) - 1) { fprintf(stream, ", "); } diff --git a/examples/z_storage.c b/examples/z_storage.c new file mode 100644 index 000000000..3eb396703 --- /dev/null +++ b/examples/z_storage.c @@ -0,0 +1,331 @@ +// +// Copyright (c) 2025 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +#include +#include + +#include "parse_args.h" +#include "zenoh.h" + +#define DEFAULT_KEYEXPR "demo/example/**" +#define STORAGE_NUM_BINS 256 + +struct node_t; +typedef struct node_t node_t; + +struct node_t { + z_owned_sample_t sample; + node_t* next; + node_t* prev; +}; + +typedef struct { + node_t** nodes; + size_t num_bins; +} storage_t; + +typedef struct { + size_t bin; + node_t* node; +} storage_iterator_t; + +storage_t storage; +z_owned_mutex_t storage_mutex; + +struct args_t { + char* keyexpr; // -k, --key + bool complete; // --complete +}; + +struct args_t parse_args(int argc, char** argv, z_owned_config_t* config); +const char* kind_to_str(z_sample_kind_t kind); + +storage_t storage_new(size_t num_bins); +void storage_insert(storage_t* storage, const z_loaned_sample_t* sample); +z_owned_sample_t* storage_find(storage_t* storage, const z_loaned_string_t* key); +void storage_remove(storage_t* storage, const z_loaned_keyexpr_t* keyexpr); +void storage_drop(storage_t* storage); +storage_iterator_t storage_begin(storage_t* storage); +bool storage_is_end(storage_t* storage, storage_iterator_t it); +z_owned_sample_t* storage_iterator_value(storage_iterator_t it); +storage_iterator_t storage_iterator_next(storage_t* storage, storage_iterator_t it); + +void sub_handler(z_loaned_sample_t* sample, void* arg) { + z_view_string_t key_string; + z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_string); + + z_owned_string_t payload_string; + z_bytes_to_string(z_sample_payload(sample), &payload_string); + + printf(">> [Subscriber] Received %s ('%.*s': '%.*s')\n", kind_to_str(z_sample_kind(sample)), + (int)z_string_len(z_loan(key_string)), z_string_data(z_loan(key_string)), + (int)z_string_len(z_loan(payload_string)), z_string_data(z_loan(payload_string))); + z_drop(z_move(payload_string)); + z_mutex_lock(z_loan_mut(storage_mutex)); + switch (z_sample_kind(sample)) { + case Z_SAMPLE_KIND_PUT: + storage_insert(&storage, sample); + break; + case Z_SAMPLE_KIND_DELETE: + storage_remove(&storage, z_sample_keyexpr(sample)); + break; + } + z_mutex_unlock(z_loan_mut(storage_mutex)); +} + +void query_handler(z_loaned_query_t* query, void* context) { + z_mutex_lock(z_loan_mut(storage_mutex)); + storage_iterator_t it = storage_begin(&storage); + while (!storage_is_end(&storage, it)) { + const z_loaned_sample_t* sample = z_loan(*storage_iterator_value(it)); + if (z_keyexpr_intersects(z_query_keyexpr(query), z_sample_keyexpr(sample))) { + z_owned_bytes_t payload; + z_bytes_clone(&payload, z_sample_payload(sample)); + z_query_reply(query, z_sample_keyexpr(sample), z_move(payload), NULL); + } + it = storage_iterator_next(&storage, it); + } + z_mutex_unlock(z_loan_mut(storage_mutex)); +} + +int main(int argc, char** argv) { + zc_init_log_from_env_or("error"); + + z_mutex_init(&storage_mutex); + storage = storage_new(STORAGE_NUM_BINS); + + z_owned_config_t config; + struct args_t args = parse_args(argc, argv, &config); + z_view_keyexpr_t ke; + z_view_keyexpr_from_str(&ke, args.keyexpr); + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config), NULL)) { + printf("Unable to open session!\n"); + exit(-1); + } + + z_owned_closure_sample_t sub_callback; + z_closure(&sub_callback, sub_handler, NULL, NULL); + printf("Declaring Subscriber on '%s'...\n", args.keyexpr); + z_owned_subscriber_t sub; + if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(sub_callback), NULL)) { + printf("Unable to declare subscriber.\n"); + exit(-1); + } + + printf("Declaring Queryable on '%s'...\n", args.keyexpr); + z_owned_closure_query_t query_callback; + z_closure(&query_callback, query_handler, NULL, (void*)args.keyexpr); + z_owned_queryable_t qable; + + z_queryable_options_t opts; + z_queryable_options_default(&opts); + opts.complete = args.complete; + + if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(query_callback), &opts) < 0) { + printf("Unable to create queryable.\n"); + exit(-1); + } + + printf("Press CTRL-C to quit...\n"); + while (1) { + z_sleep_s(1); + } + + z_drop(z_move(qable)); + z_drop(z_move(sub)); + z_drop(z_move(s)); + z_mutex_drop(z_move(storage_mutex)); + storage_drop(&storage); + return 0; +} + +void print_help() { + printf( + "\ + Usage: z_storage [OPTIONS]\n\n\ + Options:\n\ + -k, --key (optional, string, default='%s'): The selection of resources to store\n\ + --complete (optional): Declare the storage as complete w.r.t. the key expression", + DEFAULT_KEYEXPR); + printf(COMMON_HELP); +} + +struct args_t parse_args(int argc, char** argv, z_owned_config_t* config) { + _Z_CHECK_HELP; + struct args_t args; + _Z_PARSE_ARG(args.keyexpr, "k", "key", (char*), (char*)DEFAULT_KEYEXPR); + args.complete = _Z_CHECK_FLAG("complete"); + parse_zenoh_common_args(argc, argv, config); + const char* unknown_arg = check_unknown_opts(argc, argv); + if (unknown_arg) { + printf("Unknown option %s\n", unknown_arg); + exit(-1); + } + char** pos_args = parse_pos_args(argc, argv, 1); + if (!pos_args || pos_args[0]) { + printf("Unexpected positional arguments\n"); + free(pos_args); + exit(-1); + } + free(pos_args); + return args; +} + +size_t _storage_hash_string(const z_loaned_string_t* s) { + size_t hash = 5381; + size_t len = z_string_len(s); + const char* data = z_string_data(s); + for (size_t i = 0; i < len; ++i) { + hash = ((hash << 5) + hash) + (size_t)data[i]; + } + return hash; +} + +size_t _storage_compare_string(const z_loaned_string_t* s1, const z_loaned_string_t* s2) { + size_t len1 = z_string_len(s1); + const char* data1 = z_string_data(s1); + size_t len2 = z_string_len(s2); + const char* data2 = z_string_data(s2); + return len1 == len2 && strncmp(data1, data2, len1) == 0; +} + +node_t* _storage_find(node_t* hash_bin, const z_loaned_string_t* key) { + node_t* node = hash_bin; + while (node != NULL) { + z_view_string_t key_string; + z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(node->sample)), &key_string); + if (_storage_compare_string(z_loan(key_string), key)) { + return node; + } + node = node->next; + } + return NULL; +} + +z_owned_sample_t* storage_find(storage_t* storage, const z_loaned_string_t* key) { + size_t hash = _storage_hash_string(key); + size_t bin = hash % storage->num_bins; + node_t* res = _storage_find(storage->nodes[bin], key); + if (res == NULL) { + return NULL; + } + return &res->sample; +} + +void storage_insert(storage_t* storage, const z_loaned_sample_t* sample) { + z_view_string_t key; + z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key); + + size_t hash = _storage_hash_string(z_loan(key)); + size_t bin = hash % storage->num_bins; + node_t* res = _storage_find(storage->nodes[bin], z_loan(key)); + if (res != NULL) { + z_drop(z_move(res->sample)); + } else if (storage->nodes[bin] == NULL) { + res = (node_t*)z_malloc(sizeof(node_t)); + res->prev = NULL; + res->next = NULL; + storage->nodes[bin] = res; + } else { + res = storage->nodes[bin]; + while (res->next != NULL) res = res->next; + res->next = (node_t*)z_malloc(sizeof(node_t)); + res->next->prev = res; + res = res->next; + res->next = NULL; + } + z_sample_clone(&res->sample, sample); +} + +void storage_remove(storage_t* storage, const z_loaned_keyexpr_t* keyexpr) { + z_view_string_t key; + z_keyexpr_as_view_string(keyexpr, &key); + + size_t hash = _storage_hash_string(z_loan(key)); + size_t bin = hash % storage->num_bins; + node_t* res = _storage_find(storage->nodes[bin], z_loan(key)); + if (res == NULL) { + return; + } + if (res->prev == NULL) { + storage->nodes[bin] = res->next; + } else { + res->prev->next = res->next; + } + if (res->next != NULL) { + res->next->prev = res->prev; + } + + z_drop(z_move(res->sample)); + z_free(res); +} + +storage_t storage_new(size_t num_bins) { + storage_t storage; + storage.num_bins = num_bins; + storage.nodes = (node_t**)z_malloc(sizeof(node_t*) * num_bins); + for (size_t i = 0; i < num_bins; ++i) { + storage.nodes[i] = NULL; + } + return storage; +} + +void storage_drop(storage_t* storage) { + for (size_t i = 0; i < storage->num_bins; ++i) { + node_t* node = storage->nodes[i]; + while (node != NULL) { + z_drop(z_move(node->sample)); + node_t* to_free = node; + node = node->next; + z_free(to_free); + } + } + z_free(storage->nodes); +} + +storage_iterator_t _storage_first_non_empty_bin(storage_t* storage, size_t start) { + while (start < storage->num_bins) { + if (storage->nodes[start] != NULL) { + return (storage_iterator_t){.bin = start, .node = storage->nodes[start]}; + } + start++; + } + return (storage_iterator_t){.bin = start, .node = NULL}; +} + +storage_iterator_t storage_begin(storage_t* storage) { return _storage_first_non_empty_bin(storage, 0); } + +bool storage_is_end(storage_t* storage, storage_iterator_t it) { return it.bin >= storage->num_bins; } + +z_owned_sample_t* storage_iterator_value(storage_iterator_t it) { return &it.node->sample; } + +storage_iterator_t storage_iterator_next(storage_t* storage, storage_iterator_t it) { + if (it.node->next != NULL) { + return (storage_iterator_t){.bin = it.bin, .node = it.node->next}; + } + return _storage_first_non_empty_bin(storage, it.bin + 1); +} + +const char* kind_to_str(z_sample_kind_t kind) { + switch (kind) { + case Z_SAMPLE_KIND_PUT: + return "PUT"; + case Z_SAMPLE_KIND_DELETE: + return "DELETE"; + default: + return "UNKNOWN"; + } +} \ No newline at end of file diff --git a/examples/z_sub_thr.c b/examples/z_sub_thr.c index f88c83d9c..ccd43d670 100644 --- a/examples/z_sub_thr.c +++ b/examples/z_sub_thr.c @@ -102,13 +102,11 @@ int main(int argc, char **argv) { z_view_keyexpr_t ke; z_view_keyexpr_from_str(&ke, "test/thr"); - z_owned_keyexpr_t declared_ke; - z_declare_keyexpr(z_loan(s), &declared_ke, z_loan(ke)); z_stats_t *context = z_stats_make(args.samples, args.num_messages); z_owned_closure_sample_t callback; z_closure(&callback, on_sample, drop_stats, context); - if (z_declare_background_subscriber(z_loan(s), z_loan(declared_ke), z_move(callback), NULL)) { + if (z_declare_background_subscriber(z_loan(s), z_loan(ke), z_move(callback), NULL)) { printf("Unable to create subscriber.\n"); exit(-1); } @@ -118,7 +116,6 @@ int main(int argc, char **argv) { z_sleep_s(1); } - z_undeclare_keyexpr(z_loan(s), z_move(declared_ke)); z_drop(z_move(s)); return 0; } @@ -126,7 +123,7 @@ int main(int argc, char **argv) { void print_help() { printf( "\ - Usage: z_sub [OPTIONS]\n\n\ + Usage: z_sub_thr [OPTIONS]\n\n\ Options:\n\ -s, --samples (optional, number, default='%d'): Number of throughput measurements.\n\ -n, --number (optional, number, default='%d'): Number of messages in each throughput measurements.\n", diff --git a/include/zenoh_commons.h b/include/zenoh_commons.h index c696f37bb..b8e2e5e3f 100644 --- a/include/zenoh_commons.h +++ b/include/zenoh_commons.h @@ -1769,7 +1769,8 @@ ZENOHC_API uint64_t z_clock_elapsed_us(const struct z_clock_t *time); */ ZENOHC_API struct z_clock_t z_clock_now(void); /** - * Closes zenoh session. This also drops all the closure callbacks remaining from dropped, but not undeclared subscribers. + * Closes Zenoh session. This also drops all the closure callbacks remaining from not yet dropped or undeclared Zenoh entites (subscribers, queriers, etc). + * After this operation, all calls for network operations for entites declared on this session will return a error. * * @return `0` in case of success, a negative value if an error occured while closing the session. */ @@ -3296,7 +3297,7 @@ bool z_keyexpr_intersects(const struct z_loaned_keyexpr_t *left, */ ZENOHC_API z_result_t z_keyexpr_is_canon(const char *start, size_t len); /** - * Constructs key expression by performing path-joining (automatically inserting) of `left` with `right`. + * Constructs key expression by performing path-joining (automatically inserting '/' in-between) of `left` with `right`. * @return 0 in case of success, negative error code otherwise. */ ZENOHC_API diff --git a/src/keyexpr.rs b/src/keyexpr.rs index 42db04533..cb07acf9f 100644 --- a/src/keyexpr.rs +++ b/src/keyexpr.rs @@ -583,7 +583,7 @@ pub unsafe extern "C" fn z_keyexpr_concat( } } -/// Constructs key expression by performing path-joining (automatically inserting) of `left` with `right`. +/// Constructs key expression by performing path-joining (automatically inserting '/' in-between) of `left` with `right`. /// @return 0 in case of success, negative error code otherwise. #[no_mangle] pub extern "C" fn z_keyexpr_join( diff --git a/src/session.rs b/src/session.rs index 879adc9b6..4c085bf39 100644 --- a/src/session.rs +++ b/src/session.rs @@ -177,7 +177,8 @@ pub extern "C" fn z_close_options_default(this_: &mut MaybeUninit