diff --git a/iceoryx2-ffi/cxx/include/iox2/publisher.hpp b/iceoryx2-ffi/cxx/include/iox2/publisher.hpp index f678c334..1dd49482 100644 --- a/iceoryx2-ffi/cxx/include/iox2/publisher.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/publisher.hpp @@ -53,8 +53,12 @@ class Publisher { /// Copies the input `value` into a [`SampleMut`] and delivers it. /// On success it returns the number of [`Subscriber`]s that received /// the data, otherwise a [`PublisherSendError`] describing the failure. + template ::VALUE, void>> auto send_copy(const Payload& payload) const -> iox::expected; + template ::VALUE, void>> + auto send_slice_copy(const Payload& payload) const -> iox::expected; + /// Loans/allocates a [`SampleMutUninit`] from the underlying data segment of the [`Publisher`]. /// The user has to initialize the payload before it can be sent. /// @@ -167,6 +171,7 @@ inline auto Publisher::id() const -> UniquePublisherId { } template +template inline auto Publisher::send_copy(const Payload& payload) const -> iox::expected { static_assert(std::is_trivially_copyable::value); @@ -182,6 +187,25 @@ inline auto Publisher::send_copy(const Payload& payload) return iox::err(iox::into(result)); } +template +template +inline auto Publisher::send_slice_copy(const Payload& payload) const + -> iox::expected { + size_t number_of_recipients = 0; + auto result = iox2_publisher_send_slice_copy(&m_handle, + payload.data(), + sizeof(typename Payload::ValueType), + alignof(typename Payload::ValueType), + payload.number_of_elements(), + &number_of_recipients); + + if (result == IOX2_OK) { + return iox::ok(number_of_recipients); + } + + return iox::err(iox::into(result)); +} + template template inline auto Publisher::loan_uninit() diff --git a/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp b/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp index 70de3070..6b1dacdb 100644 --- a/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp +++ b/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp @@ -10,6 +10,7 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT +#include "iox/uninitialized_array.hpp" #include "iox2/node.hpp" #include "iox2/node_name.hpp" #include "iox2/service.hpp" @@ -199,10 +200,58 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_uninit_send_receive_works) { ASSERT_THAT(**recv_sample, Eq(payload)); } +TYPED_TEST(ServicePublishSubscribeTest, slice_copy_send_receive_works) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr auto SLICE_MAX_LENGTH = 10; + + constexpr uint64_t DEFAULT_VALUE_A = 42; + constexpr uint64_t DEFAULT_VALUE_B = 777; + constexpr uint64_t DEFAULT_VALUE_Z = 21; + struct MyNestedStruct { + uint64_t a { DEFAULT_VALUE_A }; + uint64_t b { DEFAULT_VALUE_B }; + }; + struct MyStruct { + uint64_t z { DEFAULT_VALUE_Z }; + MyNestedStruct data; + }; + + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service = + node.service_builder(service_name).template publish_subscribe>().create().expect(""); + + auto sut_publisher = service.publisher_builder().max_slice_len(SLICE_MAX_LENGTH).create().expect(""); + auto sut_subscriber = service.subscriber_builder().create().expect(""); + + iox::UninitializedArray elements; + for (auto& item : elements) { + new (&item) MyStruct {}; + } + auto payload = iox::Slice(elements.begin(), SLICE_MAX_LENGTH); + sut_publisher.send_slice_copy(payload).expect(""); + + auto recv_result = sut_subscriber.receive().expect(""); + ASSERT_TRUE(recv_result.has_value()); + auto recv_sample = std::move(recv_result.value()); + + auto iterations = 0; + for (const auto& item : recv_sample.payload_slice()) { + ASSERT_THAT(item.z, Eq(DEFAULT_VALUE_Z)); + ASSERT_THAT(item.data.a, Eq(DEFAULT_VALUE_A)); + ASSERT_THAT(item.data.b, Eq(DEFAULT_VALUE_B)); + ++iterations; + } + + ASSERT_THAT(recv_sample.payload_slice().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); +} + TYPED_TEST(ServicePublishSubscribeTest, loan_slice_send_receive_works) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; constexpr uint64_t PAYLOAD_ALIGNMENT = 8; - constexpr auto CXX_SLICE_MAX_LENGTH = 10; + constexpr auto SLICE_MAX_LENGTH = 10; constexpr uint64_t DEFAULT_VALUE_A = 42; constexpr uint64_t DEFAULT_VALUE_B = 777; @@ -225,10 +274,10 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_slice_send_receive_works) { .create() .expect(""); - auto sut_publisher = service.publisher_builder().max_slice_len(CXX_SLICE_MAX_LENGTH).create().expect(""); + auto sut_publisher = service.publisher_builder().max_slice_len(SLICE_MAX_LENGTH).create().expect(""); auto sut_subscriber = service.subscriber_builder().create().expect(""); - auto send_sample = sut_publisher.loan_slice(CXX_SLICE_MAX_LENGTH).expect(""); + auto send_sample = sut_publisher.loan_slice(SLICE_MAX_LENGTH).expect(""); send(std::move(send_sample)).expect(""); @@ -244,14 +293,14 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_slice_send_receive_works) { ++iterations; } - ASSERT_THAT(recv_sample.payload_slice().number_of_elements(), Eq(CXX_SLICE_MAX_LENGTH)); - ASSERT_THAT(iterations, Eq(CXX_SLICE_MAX_LENGTH)); + ASSERT_THAT(recv_sample.payload_slice().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); } TYPED_TEST(ServicePublishSubscribeTest, loan_slice_uninit_send_receive_works) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; constexpr uint64_t PAYLOAD_ALIGNMENT = 8; - constexpr auto CXX_SLICE_MAX_LENGTH = 10; + constexpr auto SLICE_MAX_LENGTH = 10; constexpr uint64_t DEFAULT_VALUE_A = 42; constexpr uint64_t DEFAULT_VALUE_B = 777; @@ -274,10 +323,10 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_slice_uninit_send_receive_works) { .create() .expect(""); - auto sut_publisher = service.publisher_builder().max_slice_len(CXX_SLICE_MAX_LENGTH).create().expect(""); + auto sut_publisher = service.publisher_builder().max_slice_len(SLICE_MAX_LENGTH).create().expect(""); auto sut_subscriber = service.subscriber_builder().create().expect(""); - auto send_sample = sut_publisher.loan_slice_uninit(CXX_SLICE_MAX_LENGTH).expect(""); + auto send_sample = sut_publisher.loan_slice_uninit(SLICE_MAX_LENGTH).expect(""); auto iterations = 0; for (auto& item : send_sample.payload_slice()) { @@ -300,14 +349,14 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_slice_uninit_send_receive_works) { ++iterations; } - ASSERT_THAT(recv_sample.payload_slice().number_of_elements(), Eq(CXX_SLICE_MAX_LENGTH)); - ASSERT_THAT(iterations, Eq(CXX_SLICE_MAX_LENGTH)); + ASSERT_THAT(recv_sample.payload_slice().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); } TYPED_TEST(ServicePublishSubscribeTest, loan_slice_uninit_with_bytes_send_receive_works) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; constexpr uint64_t PAYLOAD_ALIGNMENT = 8; - constexpr auto CXX_SLICE_MAX_LENGTH = 10; + constexpr auto SLICE_MAX_LENGTH = 10; constexpr uint64_t DEFAULT_VALUE_A = 42; constexpr uint64_t DEFAULT_VALUE_B = 777; diff --git a/iceoryx2-ffi/ffi/src/api/publisher.rs b/iceoryx2-ffi/ffi/src/api/publisher.rs index 193667a5..a3bde275 100644 --- a/iceoryx2-ffi/ffi/src/api/publisher.rs +++ b/iceoryx2-ffi/ffi/src/api/publisher.rs @@ -182,7 +182,7 @@ impl HandleToType for iox2_publisher_h_ref { unsafe fn send_copy( publisher: &Publisher, data_ptr: *const c_void, - data_len: usize, + size_of_element: usize, number_of_recipients: *mut usize, ) -> c_int { // loan_slice_uninit(1) <= 1 is correct here since it defines the number of @@ -193,6 +193,38 @@ unsafe fn send_copy( Err(e) => return e.into_c_int(), }; + if sample.payload().len() < size_of_element { + return iox2_publisher_send_error_e::LOAN_ERROR_EXCEEDS_MAX_LOAN_SIZE as c_int; + } + + let sample_ptr = sample.payload_mut().as_mut_ptr(); + core::ptr::copy_nonoverlapping(data_ptr, sample_ptr.cast(), size_of_element); + match sample.assume_init().send() { + Ok(v) => { + if !number_of_recipients.is_null() { + *number_of_recipients = v; + } + } + Err(e) => return e.into_c_int(), + } + + IOX2_OK +} + +unsafe fn send_slice_copy( + publisher: &Publisher, + data_ptr: *const c_void, + size_of_element: usize, + alignment_of_element: usize, + number_of_elements: usize, + number_of_recipients: *mut usize, +) -> c_int { + let mut sample = match publisher.loan_custom_payload(number_of_elements) { + Ok(sample) => sample, + Err(e) => return e.into_c_int(), + }; + + let data_len = (size_of_element * number_of_elements).next_multiple_of(alignment_of_element); if sample.payload().len() < data_len { return iox2_publisher_send_error_e::LOAN_ERROR_EXCEEDS_MAX_LOAN_SIZE as c_int; } @@ -316,6 +348,41 @@ pub unsafe extern "C" fn iox2_publisher_id( *id_handle_ptr = (*storage_ptr).as_handle(); } +#[no_mangle] +pub unsafe extern "C" fn iox2_publisher_send_slice_copy( + publisher_handle: iox2_publisher_h_ref, + data_ptr: *const c_void, + size_of_element: usize, + alignment_of_element: usize, + number_of_elements: usize, + number_of_recipients: *mut usize, +) -> c_int { + publisher_handle.assert_non_null(); + debug_assert!(!data_ptr.is_null()); + debug_assert!(size_of_element != 0); + + let publisher = &mut *publisher_handle.as_type(); + + match publisher.service_type { + iox2_service_type_e::IPC => send_slice_copy( + &publisher.value.as_mut().ipc, + data_ptr, + size_of_element, + alignment_of_element, + number_of_elements, + number_of_recipients, + ), + iox2_service_type_e::LOCAL => send_slice_copy( + &publisher.value.as_mut().local, + data_ptr, + size_of_element, + alignment_of_element, + number_of_elements, + number_of_recipients, + ), + } +} + /// Sends a copy of the provided data via the publisher. The data must be copyable via `memcpy`. /// /// # Arguments