From 8c35addba38db635a1950265dddfba3d11574f0b Mon Sep 17 00:00:00 2001 From: Denis Biryukov Date: Mon, 11 Mar 2024 17:25:50 +0100 Subject: [PATCH] add z_attachment_is_empty and z_bytes_map_is_empty functions --- docs/api.rst | 2 ++ include/zenoh_commons.h | 8 ++++++ src/attachment.rs | 51 ++++++++++++++++++++++++++--------- tests/z_api_attachment_test.c | 5 ++++ 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 2f6486295..ffd5b0f69 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -39,6 +39,7 @@ Bytes map .. autocfunction:: zenoh_commons.h::z_bytes_map_drop .. autocfunction:: zenoh_commons.h::z_bytes_map_get .. autocfunction:: zenoh_commons.h::z_bytes_map_len +.. autocfunction:: zenoh_commons.h::z_bytes_map_is_empty .. autocfunction:: zenoh_commons.h::z_bytes_map_insert_by_alias .. autocfunction:: zenoh_commons.h::z_bytes_map_insert_by_copy .. autocfunction:: zenoh_commons.h::z_bytes_map_iter @@ -159,6 +160,7 @@ Attachment .. autocfunction:: zenoh_commons.h::z_attachment_null .. autocfunction:: zenoh_commons.h::z_attachment_get .. autocfunction:: zenoh_commons.h::z_attachment_len +.. autocfunction:: zenoh_commons.h::z_attachment_is_empty .. autocfunction:: zenoh_commons.h::z_attachment_check .. autocfunction:: zenoh_commons.h::z_attachment_iterate diff --git a/include/zenoh_commons.h b/include/zenoh_commons.h index 310a43842..ba363f02e 100644 --- a/include/zenoh_commons.h +++ b/include/zenoh_commons.h @@ -1026,6 +1026,10 @@ ZENOHC_API bool z_attachment_check(const struct z_attachment_t *this_); * Returns the value associated with the key. */ ZENOHC_API struct z_bytes_t z_attachment_get(struct z_attachment_t this_, struct z_bytes_t key); +/** + * Returns true if `z_attachment_t` contains no key-value pairs, false otherwise. + */ +ZENOHC_API bool z_attachment_is_empty(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. @@ -1113,6 +1117,10 @@ 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); +/** + * Returns true if the map is empty, false otherwise. + */ +ZENOHC_API bool z_bytes_map_is_empty(struct z_owned_bytes_map_t *this_); /** * Iterates over the key-value pairs in the map. * diff --git a/src/attachment.rs b/src/attachment.rs index 7aadf0be5..e776fa238 100644 --- a/src/attachment.rs +++ b/src/attachment.rs @@ -115,15 +115,14 @@ pub extern "C" fn z_attachment_get(this: z_attachment_t, key: z_bytes_t) -> z_by } } -/// Returns number of key-value pairs for `z_attachment_t`. -/// -/// Does so by iterating over all existing key-value pairs. -#[no_mangle] -pub extern "C" fn z_attachment_len(this: z_attachment_t) -> usize { +fn _z_attachment_len(this: z_attachment_t, check_if_non_empty: bool) -> usize { match this.iteration_driver.as_ref() { None => 0, Some(iteration_driver) => { - let mut count: usize = 0; + struct count_context_t { + count: usize, + stop_if_not_empty: bool, + } extern "C" fn attachment_count_iterator( _key: z_bytes_t, @@ -131,22 +130,43 @@ pub extern "C" fn z_attachment_len(this: z_attachment_t) -> usize { context: *mut c_void, ) -> i8 { unsafe { - let context = &mut *(context as *mut usize); - *context += 1; - 0 + let context = &mut *(context as *mut count_context_t); + context.count += 1; + if context.stop_if_not_empty { + 1 + } else { + 0 + } } } + let mut count_context = count_context_t { + count: 0, + stop_if_not_empty: check_if_non_empty, + }; (iteration_driver)( this.data, attachment_count_iterator, - &mut count as *mut _ as *mut c_void, + &mut count_context as *mut _ as *mut c_void, ); - count + count_context.count } - } } +/// Returns number of key-value pairs for `z_attachment_t`. +/// +/// Does so by iterating over all existing key-value pairs. +#[no_mangle] +pub extern "C" fn z_attachment_len(this: z_attachment_t) -> usize { + _z_attachment_len(this, false) +} + +/// Returns true if `z_attachment_t` contains no key-value pairs, false otherwise. +#[no_mangle] +pub extern "C" fn z_attachment_is_empty(this: z_attachment_t) -> bool { + _z_attachment_len(this, true) == 0 +} + /// 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 @@ -201,6 +221,13 @@ pub extern "C" fn z_bytes_map_len(this: &mut z_owned_bytes_map_t) -> usize { this.as_ref().map(|m| m.len()).unwrap_or(0) } +/// Returns true if the map is empty, false otherwise. +#[no_mangle] +pub extern "C" fn z_bytes_map_is_empty(this: &mut z_owned_bytes_map_t) -> bool { + let this = unsafe { &*this.get() }; + this.as_ref().map(|m| m.is_empty()).unwrap_or(true) +} + /// 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` diff --git a/tests/z_api_attachment_test.c b/tests/z_api_attachment_test.c index a4246e661..737048e9b 100644 --- a/tests/z_api_attachment_test.c +++ b/tests/z_api_attachment_test.c @@ -32,6 +32,7 @@ void writting_through_map_by_alias_read_by_get() { assert(z_bytes_map_len(&map) == 2); assert(z_attachment_len(attachment) == 2); + assert(!z_attachment_is_empty(attachment)); z_bytes_t a1 = z_attachment_get(attachment, z_bytes_from_str("k1")); ASSERT_STR_BYTES_EQUAL("v1", a1); @@ -67,6 +68,7 @@ void writting_through_map_by_copy_read_by_iter() { // Elements check assert(z_bytes_map_len(&map) == 2); assert(z_attachment_len(attachment) == 2); + assert(!z_attachment_is_empty(attachment)); int res = z_attachment_iterate(attachment, _attachment_reader, (void*)42); assert(res == 24); @@ -89,6 +91,7 @@ void writting_no_map_read_by_get() { // Elements check assert(z_attachment_len(attachment) == 2); + assert(!z_attachment_is_empty(attachment)); z_bytes_t a1 = z_attachment_get(attachment, z_bytes_from_str("k1")); ASSERT_STR_BYTES_EQUAL("v1", a1); @@ -103,6 +106,8 @@ void writting_no_map_read_by_get() { void invalid_attachment_safety() { z_attachment_t attachment = z_attachment_null(); + assert(z_attachment_is_empty(attachment)); + assert(z_attachment_len(attachment) == 0); z_bytes_t a_non = z_attachment_get(attachment, z_bytes_from_str("k_non")); assert(a_non.start == NULL);