Skip to content

Commit

Permalink
allow z_bytes_map_t to alias its keys and values
Browse files Browse the repository at this point in the history
  • Loading branch information
p-avital committed Nov 15, 2023
1 parent 793db48 commit 0f98378
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 37 deletions.
13 changes: 4 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,8 @@ libc = "0.2.139"
log = "0.4.17"
rand = "0.8.5"
spin = "0.9.5"
zenoh = { git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "master", features = [
"shared-memory",
"unstable",
] }
zenoh-protocol = { git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "master", features = [
"shared-memory",
] }
zenoh = { git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "master", features = [ "shared-memory", "unstable" ] }
zenoh-protocol = { git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "master", features = [ "shared-memory" ] }
zenoh-util = { git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "master" }

[build-dependencies]
Expand All @@ -62,8 +57,8 @@ fs2 = "0.4.3"
serde_yaml = "0.9.19"

[lib]
path = "src/lib.rs"
name = "zenohc"
path="src/lib.rs"
name = "zenohcd"
crate-type = ["cdylib", "staticlib"]
doctest = false

Expand Down
9 changes: 2 additions & 7 deletions examples/z_sub.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,13 @@

const char *kind_to_str(z_sample_kind_t kind);

int8_t attachement_handler(z_bytes_t key, z_bytes_t value, void *ctx) {
(void)ctx;
printf(">> [Subscriber] attached %.*s -> %.*s", (int)key.len, key.start, (int)value.len, value.start);
return 0;
}

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->attachements)) {
z_attachement_iterate(sample->attachements, attachement_handler, NULL);
z_owned_bytes_map_t map = z_bytes_map_from_attachement(sample->attachements);
z_bytes_t there = z_bytes_map_get(&map, z_bytes_new("hello"));
}
z_drop(z_move(keystr));
}
Expand Down
48 changes: 48 additions & 0 deletions include/zenoh_commons.h
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,38 @@ ZENOHC_API bool z_bytes_map_check(const struct z_owned_bytes_map_t *this_);
* 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 attachement, 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_attachement(struct z_attachement_t this_);
/**
* Constructs a map from the provided attachement, aliasing the attachement'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_attachement_aliasing(struct z_attachement_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.
*
Expand All @@ -841,6 +873,22 @@ 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_attachement_iter_body_t body,
void *ctx);
/**
* Constructs a new map.
*/
Expand Down
133 changes: 112 additions & 21 deletions src/attachements.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::collections::HashMap;
use std::{borrow::Cow, cell::UnsafeCell, collections::HashMap};

use libc::c_void;

use crate::z_bytes_t;
use crate::{z_bytes_null, z_bytes_t};

/// The body of a loop over an attachment's key-value pairs.
///
Expand Down Expand Up @@ -88,7 +88,7 @@ pub struct z_owned_bytes_map_t {
_1: [usize; 4],
}
impl core::ops::Deref for z_owned_bytes_map_t {
type Target = core::cell::UnsafeCell<HashMap<Vec<u8>, Vec<u8>>>;
type Target = Option<UnsafeCell<HashMap<Cow<'static, [u8]>, Cow<'static, [u8]>>>>;
fn deref(&self) -> &Self::Target {
unsafe { core::mem::transmute(self) }
}
Expand All @@ -97,16 +97,13 @@ impl core::ops::Deref for z_owned_bytes_map_t {
/// Constructs a new map.
#[no_mangle]
pub extern "C" fn z_bytes_map_new() -> z_owned_bytes_map_t {
unsafe { core::mem::transmute(HashMap::<Vec<u8>, Vec<u8>>::new()) }
unsafe { core::mem::transmute(Some(HashMap::<Cow<[u8]>, Cow<[u8]>>::new())) }
}

/// Constructs the gravestone value for `z_owned_bytes_map_t`
#[no_mangle]
pub extern "C" fn z_bytes_map_null() -> z_owned_bytes_map_t {
z_owned_bytes_map_t {
_0: [0; 2],
_1: [0; 4],
}
unsafe { core::mem::transmute(None::<HashMap<Cow<[u8]>, Cow<[u8]>>>) }
}

/// Returns `true` if the map is not in its gravestone state
Expand All @@ -125,6 +122,21 @@ pub extern "C" fn z_bytes_map_drop(this: &mut z_owned_bytes_map_t) {
}
}

/// 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`
#[no_mangle]
pub extern "C" fn z_bytes_map_get(this: &z_owned_bytes_map_t, key: z_bytes_t) -> z_bytes_t {
let (Some(this), Some(key)) = (this.as_ref(), key.as_slice()) else {
return z_bytes_null();
};
if let Some(value) = unsafe { &*this.get() }.get(key) {
value.as_ref().into()
} else {
z_bytes_null()
}
}

/// 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.
Expand All @@ -134,13 +146,32 @@ pub extern "C" fn z_bytes_map_insert_by_copy(
key: z_bytes_t,
value: z_bytes_t,
) {
match (z_bytes_map_check(this), key.as_slice(), value.as_slice()) {
(true, Some(key), Some(value)) => {
unsafe { &mut *this.get() }.insert(key.to_owned(), value.to_owned());
}
_ => {
todo!()
}
if let (Some(this), Some(key), Some(value)) = (this.as_ref(), key.as_slice(), value.as_slice())
{
unsafe { &mut *this.get() }
.insert(Cow::Owned(key.to_owned()), Cow::Owned(value.to_owned()));
}
}

/// 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.
#[no_mangle]
pub extern "C" fn z_bytes_map_insert_by_alias(
this: &z_owned_bytes_map_t,
key: z_bytes_t,
value: z_bytes_t,
) {
if let (Some(this), Some(key), Some(value)) = (this.as_ref(), key.as_slice(), value.as_slice())
{
unsafe {
(*this.get()).insert(
Cow::Borrowed(core::mem::transmute(key)),
Cow::Borrowed(core::mem::transmute(value)),
)
};
}
}

Expand All @@ -149,7 +180,8 @@ pub extern "C" fn z_bytes_map_insert_by_copy(
/// Calling this with `NULL` or the gravestone value is undefined behaviour.
#[no_mangle]
extern "C" fn z_bytes_map_len(this: &z_owned_bytes_map_t) -> usize {
unsafe { &*this.get() }.len()
this.as_ref()
.map_or(0, |this| unsafe { &*this.get() }.len())
}

/// Iterates over the key-value pairs in the map.
Expand All @@ -163,15 +195,17 @@ extern "C" fn z_bytes_map_len(this: &z_owned_bytes_map_t) -> usize {
///
/// Calling this with `NULL` or the gravestone value is undefined behaviour.
#[no_mangle]
extern "C" fn z_bytes_map_iter(
pub extern "C" fn z_bytes_map_iter(
this: &z_owned_bytes_map_t,
body: z_attachement_iter_body_t,
ctx: *mut c_void,
) -> i8 {
for (key, value) in unsafe { &*this.get() }.iter() {
let result = body(key.as_slice().into(), value.as_slice().into(), ctx);
if result != 0 {
return result;
if let Some(this) = this.as_ref() {
for (key, value) in unsafe { &*this.get() }.iter() {
let result = body(key.as_ref().into(), value.as_ref().into(), ctx);
if result != 0 {
return result;
}
}
}
0
Expand Down Expand Up @@ -199,3 +233,60 @@ pub extern "C" fn z_bytes_map_as_attachement(this: &z_owned_bytes_map_t) -> z_at
}
}
}

extern "C" fn bytes_map_from_attachement_iterator(
key: z_bytes_t,
value: z_bytes_t,
ctx: *mut c_void,
) -> i8 {
let map = unsafe { &*ctx.cast::<z_owned_bytes_map_t>() };
z_bytes_map_insert_by_copy(map, key, value);
0
}
extern "C" fn bytes_map_from_attachement_iterator_by_alias(
key: z_bytes_t,
value: z_bytes_t,
ctx: *mut c_void,
) -> i8 {
let map = unsafe { &*ctx.cast::<z_owned_bytes_map_t>() };
z_bytes_map_insert_by_alias(map, key, value);
0
}

/// Constructs a map from the provided attachement, copying keys and values.
///
/// If `this` is at gravestone value, the returned value will also be at gravestone value.
#[no_mangle]
pub extern "C" fn z_bytes_map_from_attachement(this: z_attachement_t) -> z_owned_bytes_map_t {
if z_attachement_check(&this) {
let mut map = z_bytes_map_new();
z_attachement_iterate(
this,
bytes_map_from_attachement_iterator,
&mut map as *mut _ as *mut _,
);
map
} else {
z_bytes_map_null()
}
}

/// Constructs a map from the provided attachement, aliasing the attachement's keys and values.
///
/// If `this` is at gravestone value, the returned value will also be at gravestone value.
#[no_mangle]
pub extern "C" fn z_bytes_map_from_attachement_aliasing(
this: z_attachement_t,
) -> z_owned_bytes_map_t {
if z_attachement_check(&this) {
let mut map = z_bytes_map_new();
z_attachement_iterate(
this,
bytes_map_from_attachement_iterator_by_alias,
&mut map as *mut _ as *mut _,
);
map
} else {
z_bytes_map_null()
}
}

0 comments on commit 0f98378

Please sign in to comment.