Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#500] Expose UniquePortId bytes in CXX API #501

Merged
1 change: 1 addition & 0 deletions doc/release-notes/iceoryx2-unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
* Rename `iox2_publisher_loan` to `iox2_publisher_loan_slice_uninit` [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490)
1. C always loans slices, for a single element, specify the
`number_of_elements` to be 1
* APIs to retrieve the value of `UniquePortIds` from the C/C++ bindings [#500](https://github.com/eclipse-iceoryx/iceoryx2/issues/500)

### API Breaking Changes

Expand Down
19 changes: 18 additions & 1 deletion iceoryx2-ffi/cxx/include/iox2/unique_port_id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@
#ifndef IOX2_UNIQUE_PORT_ID_HPP
#define IOX2_UNIQUE_PORT_ID_HPP

#include "iox/optional.hpp"
#include "iox/vector.hpp"
#include "iox2/internal/iceoryx2.hpp"

namespace iox2 {

constexpr uint64_t UNIQUE_PORT_ID_LENGTH = 128;
orecham marked this conversation as resolved.
Show resolved Hide resolved
using RawIdType = iox::vector<uint8_t, UNIQUE_PORT_ID_LENGTH>;

/// The system-wide unique id of a [`Publisher`].
class UniquePublisherId {
public:
Expand All @@ -25,6 +31,8 @@ class UniquePublisherId {
auto operator=(UniquePublisherId&& rhs) noexcept -> UniquePublisherId&;
~UniquePublisherId();

auto bytes() const -> const iox::optional<RawIdType>&;

private:
template <ServiceType, typename, typename>
friend class Publisher;
Expand All @@ -36,9 +44,9 @@ class UniquePublisherId {
void drop();

iox2_unique_publisher_id_h m_handle = nullptr;
mutable iox::optional<RawIdType> m_raw_id;
orecham marked this conversation as resolved.
Show resolved Hide resolved
};


/// The system-wide unique id of a [`Subscriber`].
class UniqueSubscriberId {
public:
Expand All @@ -48,6 +56,8 @@ class UniqueSubscriberId {
auto operator=(UniqueSubscriberId&& rhs) noexcept -> UniqueSubscriberId&;
~UniqueSubscriberId();

auto bytes() const -> const iox::optional<RawIdType>&;

private:
template <ServiceType, typename, typename>
friend class Subscriber;
Expand All @@ -58,6 +68,7 @@ class UniqueSubscriberId {
void drop();

iox2_unique_subscriber_id_h m_handle = nullptr;
mutable iox::optional<RawIdType> m_raw_id;
};

/// The system-wide unique id of a [`Notifier`].
Expand All @@ -69,6 +80,8 @@ class UniqueNotifierId {
auto operator=(UniqueNotifierId&& rhs) noexcept -> UniqueNotifierId&;
~UniqueNotifierId();

auto bytes() const -> const iox::optional<RawIdType>&;

private:
template <ServiceType>
friend class Notifier;
Expand All @@ -79,6 +92,7 @@ class UniqueNotifierId {
void drop();

iox2_unique_notifier_id_h m_handle = nullptr;
mutable iox::optional<RawIdType> m_raw_id;
};

/// The system-wide unique id of a [`Listener`].
Expand All @@ -90,6 +104,8 @@ class UniqueListenerId {
auto operator=(UniqueListenerId&& rhs) noexcept -> UniqueListenerId&;
~UniqueListenerId();

auto bytes() const -> const iox::optional<RawIdType>&;

private:
template <ServiceType>
friend class Listener;
Expand All @@ -100,6 +116,7 @@ class UniqueListenerId {
void drop();

iox2_unique_listener_id_h m_handle = nullptr;
mutable iox::optional<RawIdType> m_raw_id;
};

auto operator==(const UniquePublisherId& lhs, const UniquePublisherId& rhs) -> bool;
Expand Down
36 changes: 36 additions & 0 deletions iceoryx2-ffi/cxx/src/unique_port_id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ UniquePublisherId::UniquePublisherId(iox2_unique_publisher_id_h handle)
: m_handle { handle } {
}

auto UniquePublisherId::bytes() const -> const iox::optional<RawIdType>& {
if (!m_raw_id.has_value() && m_handle != nullptr) {
RawIdType bytes { UNIQUE_PORT_ID_LENGTH, 0 };
iox2_unique_publisher_id_value(m_handle, bytes.data(), bytes.size());
m_raw_id.emplace(std::move(bytes));
}
return m_raw_id;
};

void UniquePublisherId::drop() {
if (m_handle != nullptr) {
iox2_unique_publisher_id_drop(m_handle);
Expand Down Expand Up @@ -81,6 +90,15 @@ UniqueSubscriberId::UniqueSubscriberId(iox2_unique_subscriber_id_h handle)
: m_handle { handle } {
}

auto UniqueSubscriberId::bytes() const -> const iox::optional<RawIdType>& {
if (!m_raw_id.has_value() && m_handle != nullptr) {
RawIdType bytes { UNIQUE_PORT_ID_LENGTH, 0 };
iox2_unique_subscriber_id_value(m_handle, bytes.data(), bytes.size());
m_raw_id.emplace(std::move(bytes));
}
return m_raw_id;
};

void UniqueSubscriberId::drop() {
if (m_handle != nullptr) {
iox2_unique_subscriber_id_drop(m_handle);
Expand Down Expand Up @@ -118,6 +136,15 @@ UniqueNotifierId::UniqueNotifierId(iox2_unique_notifier_id_h handle)
: m_handle { handle } {
}

auto UniqueNotifierId::bytes() const -> const iox::optional<RawIdType>& {
if (!m_raw_id.has_value() && m_handle != nullptr) {
RawIdType bytes { UNIQUE_PORT_ID_LENGTH, 0 };
iox2_unique_notifier_id_value(m_handle, bytes.data(), bytes.size());
m_raw_id.emplace(std::move(bytes));
}
return m_raw_id;
};

void UniqueNotifierId::drop() {
if (m_handle != nullptr) {
iox2_unique_notifier_id_drop(m_handle);
Expand Down Expand Up @@ -155,6 +182,15 @@ UniqueListenerId::UniqueListenerId(iox2_unique_listener_id_h handle)
: m_handle { handle } {
}

auto UniqueListenerId::bytes() const -> const iox::optional<RawIdType>& {
if (!m_raw_id.has_value() && m_handle != nullptr) {
RawIdType bytes { UNIQUE_PORT_ID_LENGTH, 0 };
iox2_unique_listener_id_value(m_handle, bytes.data(), bytes.size());
m_raw_id.emplace(std::move(bytes));
}
return m_raw_id;
};

void UniqueListenerId::drop() {
if (m_handle != nullptr) {
iox2_unique_listener_id_drop(m_handle);
Expand Down
22 changes: 22 additions & 0 deletions iceoryx2-ffi/cxx/tests/src/unique_port_id_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
#include "iox2/publisher.hpp"
#include "iox2/service_name.hpp"
#include "iox2/subscriber.hpp"
#include "iox2/unique_port_id.hpp"

#include "test.hpp"

#include <atomic>
#include <gtest/gtest.h>

namespace {
using namespace iox2;
Expand Down Expand Up @@ -63,6 +65,26 @@ struct UniquePortIdTest : public ::testing::Test {

TYPED_TEST_SUITE(UniquePortIdTest, iox2_testing::ServiceTypes);

TYPED_TEST(UniquePortIdTest, unique_port_id_value) {
auto null_id = iox::vector<uint8_t, iox2::UNIQUE_PORT_ID_LENGTH> { iox2::UNIQUE_PORT_ID_LENGTH, 0 };

auto unique_publisher_id = this->publisher_1.id();
ASSERT_TRUE(unique_publisher_id.bytes().has_value());
ASSERT_NE(unique_publisher_id.bytes().value(), null_id);

auto unique_subscriber_id = this->subscriber_1.id();
ASSERT_TRUE(unique_subscriber_id.bytes().has_value());
ASSERT_NE(unique_subscriber_id.bytes().value(), null_id);

auto unique_notifier_id = this->notifier_1.id();
ASSERT_TRUE(unique_notifier_id.bytes().has_value());
ASSERT_NE(unique_notifier_id.bytes().value(), null_id);

auto unique_listener_id = this->listener_1.id();
ASSERT_TRUE(unique_listener_id.bytes().has_value());
ASSERT_NE(unique_listener_id.bytes().value(), null_id);
}

TYPED_TEST(UniquePortIdTest, unique_port_id_from_same_port_is_equal) {
ASSERT_TRUE(this->listener_1.id() == this->listener_1.id());
ASSERT_TRUE(this->notifier_1.id() == this->notifier_1.id());
Expand Down
39 changes: 39 additions & 0 deletions iceoryx2-ffi/ffi/src/api/unique_listener_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,45 @@ impl HandleToType for iox2_unique_listener_id_h_ref {

// BEGIN C API

/// Retrieves the value of a unique listener ID.
///
/// # Arguments
///
/// * `handle` - A valid [`iox2_unique_listener_id_h`]
/// * `id_ptr` - Pointer to a buffer where the ID value will be written
/// * `id_length` - The length of the buffer pointed to by `id_ptr`
///
/// # Safety
///
/// * `handle` must be a valid, non-null pointer
/// * `id_ptr` must be a valid, non-null pointer to a buffer of at least `id_length` bytes
/// * `id_length` must be large enough to hold the ID value
#[no_mangle]
unsafe extern "C" fn iox2_unique_listener_id_value(
handle: iox2_unique_listener_id_h,
id_ptr: *mut u8,
id_length: usize,
) {
debug_assert!(!id_ptr.is_null());
handle.assert_non_null();

let h = &mut *handle.as_type();

if let Some(Some(id)) = (h.value.internal.as_ptr() as *const Option<UniqueListenerId>).as_ref()
orecham marked this conversation as resolved.
Show resolved Hide resolved
{
let bytes = id.value().to_ne_bytes();
debug_assert!(bytes.len() <= id_length, "id_length is too small");

unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
id_ptr,
std::cmp::min(bytes.len(), id_length),
);
}
}
}

/// This function needs to be called to destroy the unique listener id!
///
/// # Arguments
Expand Down
39 changes: 39 additions & 0 deletions iceoryx2-ffi/ffi/src/api/unique_notifier_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,45 @@ impl HandleToType for iox2_unique_notifier_id_h_ref {

// BEGIN C API

/// Retrieves the value of a unique notifier ID.
///
/// # Arguments
///
/// * `handle` - A valid [`iox2_unique_notifier_id_h`]
/// * `id_ptr` - Pointer to a buffer where the ID value will be written
/// * `id_length` - The length of the buffer pointed to by `id_ptr`
///
/// # Safety
///
/// * `handle` must be a valid, non-null pointer
/// * `id_ptr` must be a valid, non-null pointer to a buffer of at least `id_length` bytes
/// * `id_length` must be large enough to hold the ID value
#[no_mangle]
unsafe extern "C" fn iox2_unique_notifier_id_value(
handle: iox2_unique_notifier_id_h,
id_ptr: *mut u8,
orecham marked this conversation as resolved.
Show resolved Hide resolved
id_length: usize,
) {
debug_assert!(!id_ptr.is_null());
handle.assert_non_null();
orecham marked this conversation as resolved.
Show resolved Hide resolved

let h = &mut *handle.as_type();

if let Some(Some(id)) = (h.value.internal.as_ptr() as *const Option<UniqueNotifierId>).as_ref()
{
let bytes = id.value().to_ne_bytes();
debug_assert!(bytes.len() <= id_length, "id_length is too small");

unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
id_ptr,
std::cmp::min(bytes.len(), id_length),
);
}
}
}

/// This function needs to be called to destroy the unique notifier id!
///
/// # Arguments
Expand Down
39 changes: 39 additions & 0 deletions iceoryx2-ffi/ffi/src/api/unique_publisher_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,45 @@ impl HandleToType for iox2_unique_publisher_id_h_ref {

// BEGIN C API

/// Retrieves the value of a unique publisher ID.
///
/// # Arguments
///
/// * `handle` - A valid [`iox2_unique_publisher_id_h`]
/// * `id_ptr` - Pointer to a buffer where the ID value will be written
/// * `id_length` - The length of the buffer pointed to by `id_ptr`
///
/// # Safety
///
/// * `handle` must be a valid, non-null pointer
/// * `id_ptr` must be a valid, non-null pointer to a buffer of at least `id_length` bytes
/// * `id_length` must be large enough to hold the ID value
#[no_mangle]
unsafe extern "C" fn iox2_unique_publisher_id_value(
handle: iox2_unique_publisher_id_h,
id_ptr: *mut u8,
id_length: usize,
) {
debug_assert!(!id_ptr.is_null());
handle.assert_non_null();

let h = &mut *handle.as_type();

if let Some(Some(id)) = (h.value.internal.as_ptr() as *const Option<UniquePublisherId>).as_ref()
orecham marked this conversation as resolved.
Show resolved Hide resolved
{
let bytes = id.value().to_ne_bytes();
debug_assert!(bytes.len() <= id_length, "id_length is too small");

unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
id_ptr,
std::cmp::min(bytes.len(), id_length),
);
}
}
}

/// This function needs to be called to destroy the unique publisher id!
///
/// # Arguments
Expand Down
40 changes: 40 additions & 0 deletions iceoryx2-ffi/ffi/src/api/unique_subscriber_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,46 @@ impl HandleToType for iox2_unique_subscriber_id_h_ref {

// BEGIN C API

/// Retrieves the value of a unique subscriber ID.
///
/// # Arguments
///
/// * `handle` - A valid [`iox2_unique_subscriber_id_h`]
/// * `id_ptr` - Pointer to a buffer where the ID value will be written
/// * `id_length` - The length of the buffer pointed to by `id_ptr`
///
/// # Safety
///
/// * `handle` must be a valid, non-null pointer
/// * `id_ptr` must be a valid, non-null pointer to a buffer of at least `id_length` bytes
/// * `id_length` must be large enough to hold the ID value
#[no_mangle]
unsafe extern "C" fn iox2_unique_subscriber_id_value(
handle: iox2_unique_subscriber_id_h,
id_ptr: *mut u8,
id_length: usize,
) {
debug_assert!(!id_ptr.is_null());
handle.assert_non_null();

let h = &mut *handle.as_type();

if let Some(Some(id)) =
(h.value.internal.as_ptr() as *const Option<UniqueSubscriberId>).as_ref()
{
let bytes = id.value().to_ne_bytes();
debug_assert!(bytes.len() <= id_length, "id_length is too small");

unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
id_ptr,
std::cmp::min(bytes.len(), id_length),
);
}
}
}

/// This function needs to be called to destroy the unique subscriber id!
///
/// # Arguments
Expand Down
5 changes: 5 additions & 0 deletions iceoryx2/src/port/port_identifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ macro_rules! generate_id {
pub fn new() -> Self {
Self::default()
}

/// Returns the underlying raw value of the ID
orecham marked this conversation as resolved.
Show resolved Hide resolved
pub fn value(&self) -> u128 {
self.0.value()
}
}
};
}
Expand Down
Loading