diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index 8362aa404..811dfc59a 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -15,6 +15,7 @@ * Add `PeriodicTimer` into POSIX building blocks [#425](https://github.com/eclipse-iceoryx/iceoryx2/issues/425) * Developer permissions for resources [#460](https://github.com/eclipse-iceoryx/iceoryx2/issues/460) * Add `--send-copy` flag to Benchmark to consider mem operations [#483](https://github.com/eclipse-iceoryx/iceoryx2/issues/483) +* Support for slices in the C++ bindings [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490) ### Bugfixes @@ -56,7 +57,10 @@ conflicts when merging. --> -* Example text [#1](https://github.com/eclipse-iceoryx/iceoryx2/issues/1) +* APIs to support slices in the C++ bindings [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490) +* 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 ### API Breaking Changes diff --git a/examples/c/domains/src/publisher.c b/examples/c/domains/src/publisher.c index d0e164454..0ffefc71c 100644 --- a/examples/c/domains/src/publisher.c +++ b/examples/c/domains/src/publisher.c @@ -99,7 +99,7 @@ int main(int argc, char** argv) { // loan sample iox2_sample_mut_h sample = NULL; - if (iox2_publisher_loan(&publisher, NULL, &sample) != IOX2_OK) { + if (iox2_publisher_loan_slice_uninit(&publisher, NULL, &sample, 1) != IOX2_OK) { printf("Failed to loan sample\n"); goto drop_publisher; } diff --git a/examples/c/publish_subscribe/src/publisher.c b/examples/c/publish_subscribe/src/publisher.c index e3282b2bd..ead151e30 100644 --- a/examples/c/publish_subscribe/src/publisher.c +++ b/examples/c/publish_subscribe/src/publisher.c @@ -79,7 +79,7 @@ int main(void) { // loan sample iox2_sample_mut_h sample = NULL; - if (iox2_publisher_loan(&publisher, NULL, &sample) != IOX2_OK) { + if (iox2_publisher_loan_slice_uninit(&publisher, NULL, &sample, 1) != IOX2_OK) { printf("Failed to loan sample\n"); goto drop_publisher; } diff --git a/examples/c/publish_subscribe_with_user_header/src/publisher.c b/examples/c/publish_subscribe_with_user_header/src/publisher.c index 3e13075c8..b5b7d9103 100644 --- a/examples/c/publish_subscribe_with_user_header/src/publisher.c +++ b/examples/c/publish_subscribe_with_user_header/src/publisher.c @@ -92,7 +92,7 @@ int main(void) { // loan sample iox2_sample_mut_h sample = NULL; - if (iox2_publisher_loan(&publisher, NULL, &sample) != IOX2_OK) { + if (iox2_publisher_loan_slice_uninit(&publisher, NULL, &sample, 1) != IOX2_OK) { printf("Failed to loan sample\n"); goto drop_publisher; } diff --git a/examples/cxx/publish_subscribe_dynamic_data/src/publisher.cpp b/examples/cxx/publish_subscribe_dynamic_data/src/publisher.cpp index bae023812..e8c34ea3d 100644 --- a/examples/cxx/publish_subscribe_dynamic_data/src/publisher.cpp +++ b/examples/cxx/publish_subscribe_dynamic_data/src/publisher.cpp @@ -32,25 +32,25 @@ auto main() -> int { .open_or_create() .expect("successful service creation/opening"); - uint64_t worst_case_memory_size = 1024; // NOLINT - auto publisher = service.publisher_builder() - .max_slice_len(worst_case_memory_size) - .create() - .expect("successful publisher creation"); + // Since the payload type is uint8_t, this number is the same as the number of bytes in the payload. + // For other types, number of bytes used by the payload will be max_slice_len * sizeof(Payload::ValueType) + const uint64_t maximum_elements = 1024; // NOLINT + auto publisher = + service.publisher_builder().max_slice_len(maximum_elements).create().expect("successful publisher creation"); - auto counter = 1; + auto counter = 0; while (node.wait(CYCLE_TIME).has_value()) { - counter += 1; - - auto required_memory_size = (8 + counter) % 16; // NOLINT + const auto required_memory_size = (counter % 16) + 1; // NOLINT auto sample = publisher.loan_slice_uninit(required_memory_size).expect("acquire sample"); sample.write_from_fn([&](auto byte_idx) { return (byte_idx + counter) % 255; }); // NOLINT auto initialized_sample = assume_init(std::move(sample)); send(std::move(initialized_sample)).expect("send successful"); - std::cout << "Send sample " << counter << "..." << std::endl; + std::cout << "Send sample " << counter << " with " << required_memory_size << " bytes..." << std::endl; + + counter++; } std::cout << "exit" << std::endl; diff --git a/examples/cxx/publish_subscribe_dynamic_data/src/subscriber.cpp b/examples/cxx/publish_subscribe_dynamic_data/src/subscriber.cpp index fee340f43..4a789d4d3 100644 --- a/examples/cxx/publish_subscribe_dynamic_data/src/subscriber.cpp +++ b/examples/cxx/publish_subscribe_dynamic_data/src/subscriber.cpp @@ -17,6 +17,7 @@ #include "iox2/service_type.hpp" #include +#include #include constexpr iox::units::Duration CYCLE_TIME = iox::units::Duration::fromSeconds(1); @@ -35,9 +36,10 @@ auto main() -> int { while (node.wait(CYCLE_TIME).has_value()) { auto sample = subscriber.receive().expect("receive succeeds"); while (sample.has_value()) { - std::cout << "received " << sample->payload().size() << " bytes: "; - for (auto byte : sample->payload()) { - std::cout << std::hex << byte << " "; + auto payload = sample->payload(); + std::cout << "received " << std::dec << static_cast(payload.number_of_bytes()) << " bytes: "; + for (auto byte : payload) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast(byte) << " "; } std::cout << std::endl; sample = subscriber.receive().expect("receive succeeds"); diff --git a/examples/rust/publish_subscribe_dynamic_data/publisher.rs b/examples/rust/publish_subscribe_dynamic_data/publisher.rs index d729735a5..8baa001c1 100644 --- a/examples/rust/publish_subscribe_dynamic_data/publisher.rs +++ b/examples/rust/publish_subscribe_dynamic_data/publisher.rs @@ -23,24 +23,27 @@ fn main() -> Result<(), Box> { .publish_subscribe::<[u8]>() .open_or_create()?; - let worst_case_memory_size = 1024; + let maximum_elements = 1024; let publisher = service .publisher_builder() - .max_slice_len(worst_case_memory_size) + .max_slice_len(maximum_elements) .create()?; - let mut counter = 1; + let mut counter = 0; while node.wait(CYCLE_TIME).is_ok() { - counter += 1; - - let required_memory_size = (8 + counter) % 16; + let required_memory_size = (counter % 16) + 1; let sample = publisher.loan_slice_uninit(required_memory_size)?; let sample = sample.write_from_fn(|byte_idx| ((byte_idx + counter) % 255) as u8); sample.send()?; - println!("Send sample {} ...", counter); + println!( + "Send sample {} with {} bytes...", + counter, required_memory_size + ); + + counter += 1; } println!("exit"); diff --git a/iceoryx2-ffi/cxx/include/iox/slice.hpp b/iceoryx2-ffi/cxx/include/iox/slice.hpp index c0fcae70a..7edd953fe 100644 --- a/iceoryx2-ffi/cxx/include/iox/slice.hpp +++ b/iceoryx2-ffi/cxx/include/iox/slice.hpp @@ -16,38 +16,142 @@ #include "iox/assertions_addendum.hpp" #include +#include namespace iox { + +/// @brief A class representing a slice of contiguous elements of type T. +/// +/// A Slice provides a view into a contiguous sequence of elements without owning the memory. +/// It allows for efficient access and iteration over a portion of a contiguous data structure. +/// +/// @tparam T The type of elements in the slice. Can be const-qualified for read-only slices. template class Slice { public: using Iterator = T*; using ConstIterator = const T*; - using ValueType = T; - - auto size() const -> uint64_t { - IOX_TODO(); - } - auto operator[](const uint64_t n) const -> const T& { - IOX_TODO(); - } - auto operator[](const uint64_t n) -> T& { - IOX_TODO(); - } - auto begin() -> Iterator { - IOX_TODO(); - } - auto begin() const -> ConstIterator { - IOX_TODO(); - } - auto end() -> Iterator { - IOX_TODO(); - } - auto end() const -> ConstIterator { - IOX_TODO(); - } + using ValueType = std::remove_const_t; + + /// @brief Constructs a Slice object. + /// @param[in] data Pointer to the beginning of the data. + /// @param[in] number_of_elements The number of elements in the slice. + Slice(T* data, uint64_t number_of_elements); + + /// @brief Returns the total number of bytes occupied by the slice. + /// @return The number of bytes occupied by the slice, rounded up to the nearest alignment boundary. + auto number_of_bytes() const -> uint64_t; + + /// @brief Returns the number of elements in the slice. + /// @return The number of elements in the slice. + auto number_of_elements() const -> uint64_t; + + /// @brief Accesses the element at the specified index (const version). + /// @param[in] n The index of the element to access. + /// @return A const reference to the element at the specified index. + /// @pre The index must be less than the number of elements in the slice. + auto operator[](uint64_t n) const -> const ValueType&; + + /// @brief Accesses the element at the specified index (non-const version). + /// @param[in] n The index of the element to access. + /// @return A reference to the element at the specified index. + /// @pre The index must be less than the number of elements in the slice. + auto operator[](uint64_t n) -> std::conditional_t, const ValueType&, ValueType&>; + + /// @brief Returns an iterator to the beginning of the slice (const version). + /// @return An iterator pointing to the first element of the slice. + auto begin() const -> ConstIterator; + + /// @brief Returns an iterator to the beginning of the slice (non-const version). + /// @return An iterator pointing to the first element of the slice. + auto begin() -> Iterator; + + /// @brief Returns an iterator to the end of the slice (const version). + /// @return An iterator pointing one past the last element of the slice. + auto end() const -> ConstIterator; + + /// @brief Returns an iterator to the end of the slice (non-const version). + /// @return An iterator pointing one past the last element of the slice. + auto end() -> Iterator; + + /// @brief Returns a pointer to the underlying data of the slice (const version). + /// @return A pointer to the first element of the slice. + auto data() const -> ConstIterator; + + /// @brief Returns a pointer to the underlying data of the slice (non-const version). + /// @return A pointer to the first element of the slice. + auto data() -> Iterator; + + private: + T* m_data; + uint64_t m_number_of_elements; }; +template +using MutableSlice = Slice; + +template +using ImmutableSlice = Slice; + +template +Slice::Slice(T* data, uint64_t number_of_elements) + : m_data { data } + , m_number_of_elements { number_of_elements } { + static_assert(!std::is_same_v, "Slice is not allowed"); +} + +template +auto Slice::number_of_bytes() const -> uint64_t { + return (sizeof(ValueType) * m_number_of_elements + alignof(ValueType) - 1) & ~(alignof(ValueType) - 1); +} + +template +auto Slice::number_of_elements() const -> uint64_t { + return m_number_of_elements; +} + +template +auto Slice::operator[](const uint64_t n) const -> const ValueType& { + IOX_ASSERT(n < m_number_of_elements, "Index out of bounds"); + return *(m_data + n); +} + +template +auto Slice::operator[](const uint64_t n) -> std::conditional_t, const ValueType&, ValueType&> { + IOX_ASSERT(n < m_number_of_elements, "Index out of bounds"); + return *(m_data + n); +} + +template +auto Slice::begin() -> Iterator { + return m_data; +} + +template +auto Slice::begin() const -> ConstIterator { + return m_data; +} + +template +auto Slice::end() -> Iterator { + return m_data + m_number_of_elements; +} + +template +auto Slice::end() const -> ConstIterator { + return m_data + m_number_of_elements; +} + +template +auto Slice::data() -> Iterator { + return m_data; +} + +template +auto Slice::data() const -> ConstIterator { + return m_data; +} + template struct IsSlice { static constexpr bool VALUE = false; diff --git a/iceoryx2-ffi/cxx/include/iox2/payload_info.hpp b/iceoryx2-ffi/cxx/include/iox2/payload_info.hpp new file mode 100644 index 000000000..15744e964 --- /dev/null +++ b/iceoryx2-ffi/cxx/include/iox2/payload_info.hpp @@ -0,0 +1,31 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#ifndef IOX2_PAYLOAD_INFO_HPP +#define IOX2_PAYLOAD_INFO_HPP + +#include "iox/slice.hpp" + +namespace iox2 { + +template +struct PayloadInfo { + using ValueType = T; +}; + +template +struct PayloadInfo> { + using ValueType = typename iox::Slice::ValueType; +}; + +} // namespace iox2 +#endif diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp index c5b784368..9ff5d84f9 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp @@ -17,6 +17,7 @@ #include "iox/builder_addendum.hpp" #include "iox/expected.hpp" #include "iox2/internal/iceoryx2.hpp" +#include "iox2/payload_info.hpp" #include "iox2/publisher.hpp" #include "iox2/service_type.hpp" #include "iox2/unable_to_deliver_strategy.hpp" @@ -71,7 +72,9 @@ PortFactoryPublisher::create() && -> iox::expected(iox::into(value))); }); - m_max_slice_len.and_then([](auto) { IOX_TODO(); }); + m_max_slice_len + .and_then([&](auto value) { iox2_port_factory_publisher_builder_set_max_slice_len(&m_handle, value); }) + .or_else([&]() { iox2_port_factory_publisher_builder_set_max_slice_len(&m_handle, 1); }); m_max_loaned_samples.and_then( [&](auto value) { iox2_port_factory_publisher_builder_set_max_loaned_samples(&m_handle, value); }); diff --git a/iceoryx2-ffi/cxx/include/iox2/publisher.hpp b/iceoryx2-ffi/cxx/include/iox2/publisher.hpp index bec3e6bf6..3ac562139 100644 --- a/iceoryx2-ffi/cxx/include/iox2/publisher.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/publisher.hpp @@ -32,6 +32,8 @@ namespace iox2 { /// Sending endpoint of a publish-subscriber based communication. template class Publisher { + using ValueType = typename PayloadInfo::ValueType; + public: Publisher(Publisher&& rhs) noexcept; auto operator=(Publisher&& rhs) noexcept -> Publisher&; @@ -47,15 +49,24 @@ class Publisher { /// since the [`Subscriber`]s buffer is full. auto unable_to_deliver_strategy() const -> UnableToDeliverStrategy; + /// Returns the maximum number of elements that can be loaned in a slice. + template ::VALUE, void>> + auto max_slice_len() const -> uint64_t; + /// 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(iox::ImmutableSlice& 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. /// /// On failure it returns [`PublisherLoanError`] describing the failure. + template ::VALUE, void>> auto loan_uninit() -> iox::expected, PublisherLoanError>; /// Loans/allocates a [`SampleMut`] from the underlying data segment of the [`Publisher`] @@ -63,6 +74,7 @@ class Publisher { /// can be used to loan an uninitalized [`SampleMut`]. /// /// On failure it returns [`PublisherLoanError`] describing the failure. + template ::VALUE, void>> auto loan() -> iox::expected, PublisherLoanError>; /// Loans/allocates a [`SampleMut`] from the underlying data segment of the [`Publisher`] @@ -139,6 +151,13 @@ inline auto Publisher::unable_to_deliver_strategy() cons return iox::into(static_cast(iox2_publisher_unable_to_deliver_strategy(&m_handle))); } + +template +template +inline auto Publisher::max_slice_len() const -> uint64_t { + return iox2_publisher_max_slice_len(&m_handle); +} + template inline auto Publisher::id() const -> UniquePublisherId { iox2_unique_publisher_id_h id_handle = nullptr; @@ -148,6 +167,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); @@ -164,11 +184,30 @@ inline auto Publisher::send_copy(const Payload& payload) } template +template +inline auto Publisher::send_slice_copy(iox::ImmutableSlice& 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), + 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() -> iox::expected, PublisherLoanError> { SampleMutUninit sample; - auto result = iox2_publisher_loan(&m_handle, &sample.m_sample.m_sample, &sample.m_sample.m_handle); + auto result = iox2_publisher_loan_slice_uninit(&m_handle, &sample.m_sample.m_sample, &sample.m_sample.m_handle, 1); if (result == IOX2_OK) { return iox::ok(std::move(sample)); @@ -178,6 +217,7 @@ inline auto Publisher::loan_uninit() } template +template inline auto Publisher::loan() -> iox::expected, PublisherLoanError> { auto sample = loan_uninit(); @@ -195,14 +235,34 @@ template template inline auto Publisher::loan_slice(const uint64_t number_of_elements) -> iox::expected, PublisherLoanError> { - IOX_TODO(); + auto sample_uninit = loan_slice_uninit(number_of_elements); + + if (sample_uninit.has_error()) { + return iox::err(sample_uninit.error()); + } + auto sample_init = std::move(sample_uninit.value()); + + for (auto& item : sample_init.payload_mut()) { + new (&item) ValueType(); + } + + return iox::ok(assume_init(std::move(sample_init))); } template template inline auto Publisher::loan_slice_uninit(const uint64_t number_of_elements) -> iox::expected, PublisherLoanError> { - IOX_TODO(); + SampleMutUninit sample; + + auto result = iox2_publisher_loan_slice_uninit( + &m_handle, &sample.m_sample.m_sample, &sample.m_sample.m_handle, number_of_elements); + + if (result == IOX2_OK) { + return iox::ok(std::move(sample)); + } + + return iox::err(iox::into(result)); } template diff --git a/iceoryx2-ffi/cxx/include/iox2/sample.hpp b/iceoryx2-ffi/cxx/include/iox2/sample.hpp index bc95d9c15..4a1f8e5f7 100644 --- a/iceoryx2-ffi/cxx/include/iox2/sample.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/sample.hpp @@ -14,12 +14,15 @@ #define IOX2_SAMPLE_HPP #include "iox/assertions_addendum.hpp" +#include "iox/slice.hpp" #include "iox2/header_publish_subscribe.hpp" #include "iox2/internal/iceoryx2.hpp" +#include "iox2/payload_info.hpp" #include "iox2/service_type.hpp" #include "iox2/unique_port_id.hpp" namespace iox2 { + /// It stores the payload and is acquired by the [`Subscriber`] whenever /// it receives new data from a [`Publisher`] via /// [`Subscriber::receive()`]. @@ -34,6 +37,8 @@ namespace iox2 { template // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init) 'm_sample' is not used directly but only via the initialized 'm_handle'; furthermore, it will be initialized on the call site class Sample { + using ValueType = typename PayloadInfo::ValueType; + public: Sample(Sample&& rhs) noexcept; auto operator=(Sample&& rhs) noexcept -> Sample&; @@ -49,7 +54,12 @@ class Sample { auto operator->() const -> const Payload*; /// Returns a reference to the payload of the [`Sample`] - auto payload() const -> const Payload&; + template ::VALUE, void>> + auto payload() const -> const ValueType&; + + /// Returns a slice to navigate the payload of the [`Sample`] + template ::VALUE, void>> + auto payload() const -> iox::ImmutableSlice; /// Returns a reference to the user_header of the [`Sample`] template , T>> @@ -121,14 +131,24 @@ inline auto Sample::operator->() const -> const Payload* } template -inline auto Sample::payload() const -> const Payload& { - const void* payload_ptr = nullptr; - size_t payload_len = 0; +template +inline auto Sample::payload() const -> const ValueType& { + const void* ptr = nullptr; - iox2_sample_payload(&m_handle, &payload_ptr, &payload_len); - IOX_ASSERT(sizeof(Payload) <= payload_len, ""); + iox2_sample_payload(&m_handle, &ptr, nullptr); - return *static_cast(payload_ptr); + return *static_cast(ptr); +} + +template +template +inline auto Sample::payload() const -> iox::ImmutableSlice { + const void* ptr = nullptr; + size_t number_of_elements = 0; + + iox2_sample_payload(&m_handle, &ptr, &number_of_elements); + + return iox::ImmutableSlice(static_cast(ptr), number_of_elements); } template @@ -154,7 +174,6 @@ inline auto Sample::origin() const -> UniquePublisherId return header().publisher_id(); } - } // namespace iox2 #endif diff --git a/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp b/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp index dd9d04400..2451d3797 100644 --- a/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp @@ -15,9 +15,11 @@ #include "iox/assertions.hpp" #include "iox/expected.hpp" +#include "iox/slice.hpp" #include "iox2/header_publish_subscribe.hpp" #include "iox2/iceoryx2.h" #include "iox2/internal/iceoryx2.hpp" +#include "iox2/payload_info.hpp" #include "iox2/publisher_error.hpp" #include "iox2/service_type.hpp" @@ -44,6 +46,8 @@ namespace iox2 { template // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init) 'm_sample' is not used directly but only via the initialized 'm_handle'; furthermore, it will be initialized on the call site class SampleMut { + using ValueType = typename PayloadInfo::ValueType; + public: SampleMut(SampleMut&& rhs) noexcept; auto operator=(SampleMut&& rhs) noexcept -> SampleMut&; @@ -76,10 +80,18 @@ class SampleMut { auto user_header_mut() -> T&; /// Returns a reference to the const payload of the sample. - auto payload() const -> const Payload&; + template ::VALUE, void>> + auto payload() const -> const ValueType&; /// Returns a reference to the payload of the sample. - auto payload_mut() -> Payload&; + template ::VALUE, void>> + auto payload_mut() -> ValueType&; + + template ::VALUE, void>> + auto payload() const -> iox::ImmutableSlice; + + template ::VALUE, void>> + auto payload_mut() -> iox::MutableSlice; private: template @@ -186,25 +198,45 @@ inline auto SampleMut::user_header_mut() -> T& { } template -inline auto SampleMut::payload() const -> const Payload& { +template +inline auto SampleMut::payload() const -> const ValueType& { const void* ptr = nullptr; - size_t payload_len = 0; - iox2_sample_mut_payload(&m_handle, &ptr, &payload_len); - IOX_ASSERT(sizeof(Payload) <= payload_len, ""); + iox2_sample_mut_payload(&m_handle, &ptr, nullptr); - return *static_cast(ptr); + return *static_cast(ptr); } template -inline auto SampleMut::payload_mut() -> Payload& { +template +inline auto SampleMut::payload_mut() -> ValueType& { + void* ptr = nullptr; + + iox2_sample_mut_payload_mut(&m_handle, &ptr, nullptr); + + return *static_cast(ptr); +} + +template +template +inline auto SampleMut::payload() const -> iox::ImmutableSlice { + const void* ptr = nullptr; + size_t number_of_elements = 0; + + iox2_sample_mut_payload(&m_handle, &ptr, &number_of_elements); + + return iox::ImmutableSlice(static_cast(ptr), number_of_elements); +} + +template +template +inline auto SampleMut::payload_mut() -> iox::MutableSlice { void* ptr = nullptr; - size_t payload_len = 0; + size_t number_of_elements = 0; - iox2_sample_mut_payload_mut(&m_handle, &ptr, &payload_len); - IOX_ASSERT(sizeof(Payload) <= payload_len, ""); + iox2_sample_mut_payload_mut(&m_handle, &ptr, &number_of_elements); - return *static_cast(ptr); + return iox::MutableSlice(static_cast(ptr), number_of_elements); } template diff --git a/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp b/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp index 886f25ba8..b90dc6489 100644 --- a/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp @@ -24,6 +24,8 @@ namespace iox2 { template // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init) 'm_sample' is not used directly but only via the initialized 'm_handle'; furthermore, it will be initialized on the call site class SampleMutUninit { + using ValueType = typename PayloadInfo::ValueType; + public: SampleMutUninit(SampleMutUninit&& rhs) noexcept = default; auto operator=(SampleMutUninit&& rhs) noexcept -> SampleMutUninit& = default; @@ -56,10 +58,18 @@ class SampleMutUninit { auto user_header_mut() -> T&; /// Returns a reference to the const payload of the sample. - auto payload() const -> const Payload&; + template ::VALUE, void>> + auto payload() const -> const ValueType&; /// Returns a reference to the payload of the sample. - auto payload_mut() -> Payload&; + template ::VALUE, void>> + auto payload_mut() -> ValueType&; + + template ::VALUE, void>> + auto payload() const -> iox::ImmutableSlice; + + template ::VALUE, void>> + auto payload_mut() -> iox::MutableSlice; /// Writes the payload to the sample template ::VALUE, T>> @@ -71,7 +81,7 @@ class SampleMutUninit { /// mem copies the value to the sample template ::VALUE, T>> - void write_from_slice(const T& value); + void write_from_slice(iox::ImmutableSlice& value); private: template @@ -132,12 +142,26 @@ inline auto SampleMutUninit::user_header_mut() -> T& { } template -inline auto SampleMutUninit::payload() const -> const Payload& { +template +inline auto SampleMutUninit::payload() const -> const ValueType& { return m_sample.payload(); } template -inline auto SampleMutUninit::payload_mut() -> Payload& { +template +inline auto SampleMutUninit::payload_mut() -> ValueType& { + return m_sample.payload_mut(); +} + +template +template +inline auto SampleMutUninit::payload() const -> iox::ImmutableSlice { + return m_sample.payload(); +} + +template +template +inline auto SampleMutUninit::payload_mut() -> iox::MutableSlice { return m_sample.payload_mut(); } @@ -151,13 +175,19 @@ template template inline void SampleMutUninit::write_from_fn( const iox::function& initializer) { - IOX_TODO(); + auto slice = payload_mut(); + for (uint64_t i = 0; i < slice.number_of_elements(); ++i) { + new (&slice[i]) typename T::ValueType(initializer(i)); + } } template template -inline void SampleMutUninit::write_from_slice(const T& value) { - IOX_TODO(); +inline void SampleMutUninit::write_from_slice(iox::ImmutableSlice& value) { + auto dest = payload_mut(); + IOX_ASSERT(dest.number_of_bytes() >= value.number_of_bytes(), + "Destination payload size is smaller than source slice size"); + std::memcpy(dest.begin(), value.begin(), value.number_of_bytes()); } } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp b/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp index 9db74ce67..bcbfa00e3 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp @@ -19,6 +19,7 @@ #include "iox2/attribute_specifier.hpp" #include "iox2/attribute_verifier.hpp" #include "iox2/internal/iceoryx2.hpp" +#include "iox2/payload_info.hpp" #include "iox2/port_factory_publish_subscribe.hpp" #include "iox2/service_builder_publish_subscribe_error.hpp" #include "iox2/service_type.hpp" @@ -26,6 +27,7 @@ #include namespace iox2 { + /// Builder to create new [`MessagingPattern::PublishSubscribe`] based [`Service`]s template class ServiceBuilderPublishSubscribe { @@ -125,7 +127,6 @@ inline ServiceBuilderPublishSubscribe::ServiceBuilderPub template inline void ServiceBuilderPublishSubscribe::set_parameters() { - m_payload_alignment.and_then([](auto) { IOX_TODO(); }); m_enable_safe_overflow.and_then( [&](auto value) { iox2_service_builder_pub_sub_set_enable_safe_overflow(&m_handle, value); }); m_subscriber_max_borrowed_samples.and_then( @@ -135,20 +136,21 @@ inline void ServiceBuilderPublishSubscribe::set_paramete [&](auto value) { iox2_service_builder_pub_sub_set_subscriber_max_buffer_size(&m_handle, value); }); m_max_subscribers.and_then([&](auto value) { iox2_service_builder_pub_sub_set_max_subscribers(&m_handle, value); }); m_max_publishers.and_then([&](auto value) { iox2_service_builder_pub_sub_set_max_publishers(&m_handle, value); }); + m_payload_alignment.and_then( + [&](auto value) { iox2_service_builder_pub_sub_set_payload_alignment(&m_handle, value); }); m_max_nodes.and_then([&](auto value) { iox2_service_builder_pub_sub_set_max_nodes(&m_handle, value); }); + using ValueType = typename PayloadInfo::ValueType; + auto type_variant = iox::IsSlice::VALUE ? iox2_type_variant_e_DYNAMIC : iox2_type_variant_e_FIXED_SIZE; + // payload type details - const auto* payload_type_name = typeid(Payload).name(); + const auto* payload_type_name = typeid(ValueType).name(); const auto payload_type_name_len = strlen(payload_type_name); - const auto payload_type_size = sizeof(Payload); - const auto payload_type_align = alignof(Payload); + const auto payload_type_size = sizeof(ValueType); + const auto payload_type_align = alignof(ValueType); - const auto payload_result = iox2_service_builder_pub_sub_set_payload_type_details(&m_handle, - iox2_type_variant_e_FIXED_SIZE, - payload_type_name, - payload_type_name_len, - payload_type_size, - payload_type_align); + const auto payload_result = iox2_service_builder_pub_sub_set_payload_type_details( + &m_handle, type_variant, payload_type_name, payload_type_name_len, payload_type_size, payload_type_align); if (payload_result != IOX2_OK) { IOX_PANIC("This should never happen! Implementation failure while setting the Payload-Type."); @@ -161,13 +163,12 @@ inline void ServiceBuilderPublishSubscribe::set_paramete const auto user_header_type_size = header_layout.size(); const auto user_header_type_align = header_layout.alignment(); - const auto user_header_result = - iox2_service_builder_pub_sub_set_user_header_type_details(&m_handle, - iox2_type_variant_e_FIXED_SIZE, - user_header_type_name, - user_header_type_name_len, - user_header_type_size, - user_header_type_align); + const auto user_header_result = iox2_service_builder_pub_sub_set_user_header_type_details(&m_handle, + type_variant, + user_header_type_name, + user_header_type_name_len, + user_header_type_size, + user_header_type_align); if (user_header_result != IOX2_OK) { IOX_PANIC("This should never happen! Implementation failure while setting the User-Header-Type."); 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 3e4be6f07..1cd702f8b 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" @@ -178,7 +179,7 @@ TYPED_TEST(ServicePublishSubscribeTest, send_copy_receive_works) { ASSERT_THAT(**sample, Eq(payload)); } -TYPED_TEST(ServicePublishSubscribeTest, loan_uninit_send_receive_works) { +TYPED_TEST(ServicePublishSubscribeTest, loan_send_receive_works) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; const auto service_name = iox2_testing::generate_service_name(); @@ -189,17 +190,17 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_uninit_send_receive_works) { auto sut_publisher = service.publisher_builder().create().expect(""); auto sut_subscriber = service.subscriber_builder().create().expect(""); - auto sample = sut_publisher.loan_uninit().expect(""); - const uint64_t payload = 78123791; - sample.write_payload(payload); - send(assume_init(std::move(sample))).expect(""); + auto sample = sut_publisher.loan().expect(""); + const uint64_t payload = 781891729871; + *sample = payload; + send(std::move(sample)).expect(""); auto recv_sample = sut_subscriber.receive().expect(""); ASSERT_TRUE(recv_sample.has_value()); ASSERT_THAT(**recv_sample, Eq(payload)); } -TYPED_TEST(ServicePublishSubscribeTest, loan_send_receive_works) { +TYPED_TEST(ServicePublishSubscribeTest, loan_uninit_send_receive_works) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; const auto service_name = iox2_testing::generate_service_name(); @@ -210,16 +211,246 @@ TYPED_TEST(ServicePublishSubscribeTest, loan_send_receive_works) { auto sut_publisher = service.publisher_builder().create().expect(""); auto sut_subscriber = service.subscriber_builder().create().expect(""); - auto sample = sut_publisher.loan().expect(""); - const uint64_t payload = 781891729871; - *sample = payload; - send(std::move(sample)).expect(""); + auto sample = sut_publisher.loan_uninit().expect(""); + const uint64_t payload = 78123791; + sample.write_payload(payload); + send(assume_init(std::move(sample))).expect(""); auto recv_sample = sut_subscriber.receive().expect(""); ASSERT_TRUE(recv_sample.has_value()); ASSERT_THAT(**recv_sample, Eq(payload)); } +struct DummyData { + static constexpr uint64_t DEFAULT_VALUE_A = 42; + static constexpr bool DEFAULT_VALUE_Z { false }; + uint64_t a { DEFAULT_VALUE_A }; + bool z { DEFAULT_VALUE_Z }; +}; + +// NOLINTBEGIN(readability-function-cognitive-complexity) : Cognitive complexity of 26 (+1) is OK. Test case is complex. +TYPED_TEST(ServicePublishSubscribeTest, slice_copy_send_receive_works) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr auto SLICE_MAX_LENGTH = 10; + + 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) DummyData {}; + } + auto payload = iox::ImmutableSlice(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()) { + ASSERT_THAT(item.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(item.z, Eq(DummyData::DEFAULT_VALUE_Z)); + ++iterations; + } + + ASSERT_THAT(recv_sample.payload().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); +} +// NOLINTEND(readability-function-cognitive-complexity) + +TYPED_TEST(ServicePublishSubscribeTest, loan_slice_send_receive_works) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t PAYLOAD_ALIGNMENT = 8; + constexpr auto SLICE_MAX_LENGTH = 10; + + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service = node.service_builder(service_name) + .template publish_subscribe>() + .payload_alignment(PAYLOAD_ALIGNMENT) + .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(SLICE_MAX_LENGTH).expect(""); + + send(std::move(send_sample)).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()) { + ASSERT_THAT(item.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(item.z, Eq(DummyData::DEFAULT_VALUE_Z)); + ++iterations; + } + + ASSERT_THAT(recv_sample.payload().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); +} + +// NOLINTBEGIN(readability-function-cognitive-complexity) : Cognitive complexity of 26 (+1) is OK. Test case is complex. +TYPED_TEST(ServicePublishSubscribeTest, loan_slice_uninit_send_receive_works) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t PAYLOAD_ALIGNMENT = 8; + constexpr auto SLICE_MAX_LENGTH = 10; + + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service = node.service_builder(service_name) + .template publish_subscribe>() + .payload_alignment(PAYLOAD_ALIGNMENT) + .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(SLICE_MAX_LENGTH).expect(""); + + auto iterations = 0; + for (auto& item : send_sample.payload_mut()) { + new (&item) DummyData { DummyData::DEFAULT_VALUE_A + iterations, iterations % 2 == 0 }; + ++iterations; + } + + send(assume_init(std::move(send_sample))).expect(""); + + auto recv_result = sut_subscriber.receive().expect(""); + ASSERT_TRUE(recv_result.has_value()); + auto recv_sample = std::move(recv_result.value()); + + iterations = 0; + for (const auto& item : recv_sample.payload()) { + ASSERT_THAT(item.a, Eq(DummyData::DEFAULT_VALUE_A + iterations)); + ASSERT_THAT(item.z, Eq(iterations % 2 == 0)); + ++iterations; + } + + ASSERT_THAT(recv_sample.payload().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); +} +// NOLINTEND(readability-function-cognitive-complexity) + +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 SLICE_MAX_LENGTH = 10; + + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service = node.service_builder(service_name) + .template publish_subscribe>() + .payload_alignment(PAYLOAD_ALIGNMENT) + .create() + .expect(""); + + auto sut_publisher = service.publisher_builder().max_slice_len(sizeof(DummyData)).create().expect(""); + auto sut_subscriber = service.subscriber_builder().create().expect(""); + + auto send_sample = sut_publisher.loan_slice_uninit(sizeof(DummyData)).expect(""); + + new (send_sample.payload_mut().data()) DummyData {}; + + send(assume_init(std::move(send_sample))).expect(""); + + auto recv_result = sut_subscriber.receive().expect(""); + ASSERT_TRUE(recv_result.has_value()); + + auto recv_sample = std::move(recv_result.value()); + ASSERT_THAT(recv_sample.payload().number_of_elements(), Eq(sizeof(DummyData))); + const auto* recv_data = reinterpret_cast(recv_sample.payload().data()); // NOLINT + + ASSERT_THAT(recv_data->a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(recv_data->z, Eq(DummyData::DEFAULT_VALUE_Z)); +} + +TYPED_TEST(ServicePublishSubscribeTest, write_from_fn_send_receive_works) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr auto SLICE_MAX_LENGTH = 10; + + 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(""); + + auto send_sample = sut_publisher.loan_slice_uninit(SLICE_MAX_LENGTH).expect(""); + send_sample.write_from_fn( + [](auto index) { return DummyData { DummyData::DEFAULT_VALUE_A + index, index % 2 == 0 }; }); + send(assume_init(std::move(send_sample))).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()) { + ASSERT_THAT(item.a, Eq(DummyData::DEFAULT_VALUE_A + iterations)); + ASSERT_THAT(item.z, Eq(iterations % 2 == 0)); + ++iterations; + } + + ASSERT_THAT(recv_sample.payload().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); +} + +// NOLINTBEGIN(readability-function-cognitive-complexity) +TYPED_TEST(ServicePublishSubscribeTest, write_from_slice_send_receive_works) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr auto SLICE_MAX_LENGTH = 10; + + 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) DummyData {}; + } + auto payload = iox::ImmutableSlice(elements.begin(), SLICE_MAX_LENGTH); + auto send_sample = sut_publisher.loan_slice_uninit(SLICE_MAX_LENGTH).expect(""); + send_sample.write_from_slice(payload); + send(assume_init(std::move(send_sample))).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()) { + ASSERT_THAT(item.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(item.z, Eq(DummyData::DEFAULT_VALUE_Z)); + ++iterations; + } + + ASSERT_THAT(recv_sample.payload().number_of_elements(), Eq(SLICE_MAX_LENGTH)); + ASSERT_THAT(iterations, Eq(SLICE_MAX_LENGTH)); +} +// NOLINTEND(readability-function-cognitive-complexity) + TYPED_TEST(ServicePublishSubscribeTest, update_connections_delivers_history) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; @@ -252,6 +483,7 @@ TYPED_TEST(ServicePublishSubscribeTest, setting_service_properties_works) { constexpr uint64_t HISTORY_SIZE = 13; constexpr uint64_t SUBSCRIBER_MAX_BUFFER_SIZE = 14; constexpr uint64_t SUBSCRIBER_MAX_BORROWED_SAMPLES = 15; + constexpr uint64_t PAYLOAD_ALIGNMENT = 4; const auto service_name = iox2_testing::generate_service_name(); @@ -264,6 +496,7 @@ TYPED_TEST(ServicePublishSubscribeTest, setting_service_properties_works) { .history_size(HISTORY_SIZE) .subscriber_max_buffer_size(SUBSCRIBER_MAX_BUFFER_SIZE) .subscriber_max_borrowed_samples(SUBSCRIBER_MAX_BORROWED_SAMPLES) + .payload_alignment(PAYLOAD_ALIGNMENT) .create() .expect(""); @@ -363,6 +596,22 @@ TYPED_TEST(ServicePublishSubscribeTest, publisher_applies_unable_to_deliver_stra ASSERT_THAT(sut_pub_2.unable_to_deliver_strategy(), Eq(UnableToDeliverStrategy::DiscardSample)); } +TYPED_TEST(ServicePublishSubscribeTest, publisher_applies_max_slice_len) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t DESIRED_MAX_SLICE_LEN = 10; + using ValueType = uint8_t; + + 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 = service.publisher_builder().max_slice_len(DESIRED_MAX_SLICE_LEN).create().expect(""); + + ASSERT_THAT(sut.max_slice_len(), Eq(DESIRED_MAX_SLICE_LEN)); +} + TYPED_TEST(ServicePublishSubscribeTest, send_receive_with_user_header_works) { constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; diff --git a/iceoryx2-ffi/cxx/tests/src/slice_tests.cpp b/iceoryx2-ffi/cxx/tests/src/slice_tests.cpp new file mode 100644 index 000000000..d9ff1aeb2 --- /dev/null +++ b/iceoryx2-ffi/cxx/tests/src/slice_tests.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox/slice.hpp" +#include "test.hpp" + +#include + +namespace { + +struct DummyData { + static constexpr uint64_t DEFAULT_VALUE_A = 42; + static constexpr bool DEFAULT_VALUE_Z { false }; + uint64_t a { DEFAULT_VALUE_A }; + bool z { DEFAULT_VALUE_Z }; +}; + +TEST(SliceTest, const_correctness_is_maintained) { + constexpr uint64_t SLICE_MAX_LENGTH = 10; + + auto elements = std::array {}; + + auto mutable_slice = iox::MutableSlice(elements.data(), SLICE_MAX_LENGTH); + ASSERT_FALSE(std::is_const_v>); + ASSERT_FALSE(std::is_const_v>); + ASSERT_FALSE(std::is_const_v>); + ASSERT_FALSE(std::is_const_v>); + + // const instances of MutableSlice are also not mutable + const auto const_mutable_slice = iox::MutableSlice(elements.data(), SLICE_MAX_LENGTH); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + + auto immutable_slice = iox::ImmutableSlice(elements.data(), SLICE_MAX_LENGTH); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + + const auto const_immutable_slice = iox::ImmutableSlice(elements.data(), SLICE_MAX_LENGTH); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); + ASSERT_TRUE(std::is_const_v>); +} + +TEST(SliceTest, can_iterate_mutable_slice) { + constexpr uint64_t SLICE_MAX_LENGTH = 10; + + auto elements = std::array {}; + + auto mutable_slice = iox::MutableSlice(elements.data(), SLICE_MAX_LENGTH); + auto iterations = 0; + for (auto element : mutable_slice) { + ASSERT_THAT(element.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(element.z, Eq(DummyData::DEFAULT_VALUE_Z)); + iterations++; + } + ASSERT_EQ(iterations, SLICE_MAX_LENGTH); +} + +TEST(SliceTest, can_iterate_const_mutable_slice) { + constexpr uint64_t SLICE_MAX_LENGTH = 10; + + auto elements = std::array {}; + + const auto slice = iox::MutableSlice(elements.data(), SLICE_MAX_LENGTH); + auto iterations = 0; + for (auto element : slice) { + ASSERT_THAT(element.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(element.z, Eq(DummyData::DEFAULT_VALUE_Z)); + iterations++; + } + ASSERT_EQ(iterations, SLICE_MAX_LENGTH); +} + +TEST(SliceTest, can_iterate_immutable_slice) { + constexpr uint64_t SLICE_MAX_LENGTH = 10; + + auto elements = std::array {}; + + auto slice = iox::ImmutableSlice(elements.data(), SLICE_MAX_LENGTH); + auto iterations = 0; + for (auto element : slice) { + ASSERT_THAT(element.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(element.z, Eq(DummyData::DEFAULT_VALUE_Z)); + iterations++; + } + ASSERT_EQ(iterations, SLICE_MAX_LENGTH); +} + +TEST(SliceTest, can_iterate_const_immutable_slice) { + constexpr uint64_t SLICE_MAX_LENGTH = 10; + + auto elements = std::array {}; + + const auto slice = iox::ImmutableSlice(elements.data(), SLICE_MAX_LENGTH); + auto iterations = 0; + for (auto element : slice) { + ASSERT_THAT(element.a, Eq(DummyData::DEFAULT_VALUE_A)); + ASSERT_THAT(element.z, Eq(DummyData::DEFAULT_VALUE_Z)); + iterations++; + } + ASSERT_EQ(iterations, SLICE_MAX_LENGTH); +} + +} // namespace diff --git a/iceoryx2-ffi/ffi/src/api/port_factory_publisher_builder.rs b/iceoryx2-ffi/ffi/src/api/port_factory_publisher_builder.rs index 20750c57b..c3f68d9ee 100644 --- a/iceoryx2-ffi/ffi/src/api/port_factory_publisher_builder.rs +++ b/iceoryx2-ffi/ffi/src/api/port_factory_publisher_builder.rs @@ -173,6 +173,43 @@ impl HandleToType for iox2_port_factory_publisher_builder_h_ref { // BEGIN C API +/// Sets the max slice length for the publisher +/// +/// # Arguments +/// +/// * `port_factory_handle` - Must be a valid [`iox2_port_factory_publisher_builder_h_ref`] +/// obtained by [`iox2_port_factory_pub_sub_publisher_builder`](crate::iox2_port_factory_pub_sub_publisher_builder). +/// * `value` - The value to set max slice length to +/// +/// # Safety +/// +/// * `port_factory_handle` must be valid handles +#[no_mangle] +pub unsafe extern "C" fn iox2_port_factory_publisher_builder_set_max_slice_len( + port_factory_handle: iox2_port_factory_publisher_builder_h_ref, + value: c_size_t, +) { + port_factory_handle.assert_non_null(); + + let port_factory_struct = unsafe { &mut *port_factory_handle.as_type() }; + match port_factory_struct.service_type { + iox2_service_type_e::IPC => { + let port_factory = ManuallyDrop::take(&mut port_factory_struct.value.as_mut().ipc); + + port_factory_struct.set(PortFactoryPublisherBuilderUnion::new_ipc( + port_factory.max_slice_len(value), + )); + } + iox2_service_type_e::LOCAL => { + let port_factory = ManuallyDrop::take(&mut port_factory_struct.value.as_mut().local); + + port_factory_struct.set(PortFactoryPublisherBuilderUnion::new_local( + port_factory.max_slice_len(value), + )); + } + } +} + /// Sets the max loaned samples for the publisher /// /// # Arguments diff --git a/iceoryx2-ffi/ffi/src/api/publisher.rs b/iceoryx2-ffi/ffi/src/api/publisher.rs index 142b68e45..c7562eedd 100644 --- a/iceoryx2-ffi/ffi/src/api/publisher.rs +++ b/iceoryx2-ffi/ffi/src/api/publisher.rs @@ -72,18 +72,14 @@ impl IntoCInt for PublisherSendError { impl IntoCInt for PublisherLoanError { fn into_c_int(self) -> c_int { (match self { - PublisherLoanError::OutOfMemory => { - iox2_publisher_send_error_e::LOAN_ERROR_OUT_OF_MEMORY - } + PublisherLoanError::OutOfMemory => iox2_publisher_loan_error_e::OUT_OF_MEMORY, PublisherLoanError::ExceedsMaxLoanedSamples => { - iox2_publisher_send_error_e::LOAN_ERROR_EXCEEDS_MAX_LOANED_SAMPLES + iox2_publisher_loan_error_e::EXCEEDS_MAX_LOANED_SAMPLES } PublisherLoanError::ExceedsMaxLoanSize => { - iox2_publisher_send_error_e::LOAN_ERROR_EXCEEDS_MAX_LOAN_SIZE - } - PublisherLoanError::InternalFailure => { - iox2_publisher_send_error_e::LOAN_ERROR_INTERNAL_FAILURE + iox2_publisher_loan_error_e::EXCEEDS_MAX_LOAN_SIZE } + PublisherLoanError::InternalFailure => iox2_publisher_loan_error_e::INTERNAL_FAILURE, }) as c_int } } @@ -186,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 @@ -197,6 +193,37 @@ 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, + 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; if sample.payload().len() < data_len { return iox2_publisher_send_error_e::LOAN_ERROR_EXCEEDS_MAX_LOAN_SIZE as c_int; } @@ -253,6 +280,31 @@ pub unsafe extern "C" fn iox2_publisher_unable_to_deliver_strategy( } } +/// Returns the maximum `[u8]` length that can be loaned in one sample, i.e. the max number of +/// elements in the `[u8]` payload type used by the C binding. +/// +/// # Arguments +/// +/// * `publisher_handle` obtained by [`iox2_port_factory_publisher_builder_create`](crate::iox2_port_factory_publisher_builder_create) +/// +/// Returns the maximum number of elements as a [`c_int`]. +/// +/// # Safety +/// +/// * `publisher_handle` is valid and non-null +#[no_mangle] +pub unsafe extern "C" fn iox2_publisher_max_slice_len( + publisher_handle: iox2_publisher_h_ref, +) -> c_int { + publisher_handle.assert_non_null(); + + let publisher = &mut *publisher_handle.as_type(); + match publisher.service_type { + iox2_service_type_e::IPC => publisher.value.as_mut().ipc.max_slice_len() as c_int, + iox2_service_type_e::LOCAL => publisher.value.as_mut().local.max_slice_len() as c_int, + } +} + /// Returns the unique port id of the publisher. /// /// # Arguments @@ -295,6 +347,59 @@ pub unsafe extern "C" fn iox2_publisher_id( *id_handle_ptr = (*storage_ptr).as_handle(); } +/// Sends a copy of the provided slice data via the publisher. +/// +/// # Arguments +/// +/// * `publisher_handle` - Handle to the publisher obtained from `iox2_port_factory_publisher_builder_create` +/// * `data_ptr` - Pointer to the start of the slice data to be sent +/// * `size_of_element` - Size of each element in the slice in bytes +/// * `number_of_elements` - Number of elements in the slice +/// * `number_of_recipients` - Optional pointer to store the number of subscribers that received the data +/// +/// # Returns +/// +/// Returns `IOX2_OK` on success, otherwise an error code from `iox2_publisher_send_error_e` +/// +/// # Safety +/// +/// * `publisher_handle` must be valid and non-null +/// * `data_ptr` must be a valid pointer to the start of the slice data +/// * `size_of_element` must be the correct size of each element in bytes +/// * `number_of_elements` must accurately represent the number of elements in the slice +/// * `number_of_recipients` can be null, otherwise it must be a valid pointer to a `usize` +#[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, + 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, + number_of_elements, + number_of_recipients, + ), + iox2_service_type_e::LOCAL => send_slice_copy( + &publisher.value.as_mut().local, + data_ptr, + size_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 @@ -349,6 +454,7 @@ pub unsafe extern "C" fn iox2_publisher_send_copy( /// * `sample_struct_ptr` - Must be either a NULL pointer or a pointer to a valid [`iox2_sample_mut_t`]. /// If it is a NULL pointer, the storage will be allocated on the heap. /// * `sample_handle_ptr` - An uninitialized or dangling [`iox2_sample_mut_h`] handle which will be initialized by this function call if a sample is obtained, otherwise it will be set to NULL. +/// * `number_of_bytes` - The number of bytes to loan from the publisher's payload segment /// /// Return [`IOX2_OK`] on success, otherwise [`iox2_publisher_loan_error_e`]. /// @@ -357,10 +463,11 @@ pub unsafe extern "C" fn iox2_publisher_send_copy( /// * `publisher_handle` is valid and non-null /// * The `sample_handle_ptr` is pointing to a valid [`iox2_sample_mut_h`]. #[no_mangle] -pub unsafe extern "C" fn iox2_publisher_loan( +pub unsafe extern "C" fn iox2_publisher_loan_slice_uninit( publisher_handle: iox2_publisher_h_ref, sample_struct_ptr: *mut iox2_sample_mut_t, sample_handle_ptr: *mut iox2_sample_mut_h, + number_of_elements: usize, ) -> c_int { publisher_handle.assert_non_null(); debug_assert!(!sample_handle_ptr.is_null()); @@ -383,7 +490,12 @@ pub unsafe extern "C" fn iox2_publisher_loan( let publisher = &mut *publisher_handle.as_type(); match publisher.service_type { - iox2_service_type_e::IPC => match publisher.value.as_ref().ipc.loan_custom_payload(1) { + iox2_service_type_e::IPC => match publisher + .value + .as_ref() + .ipc + .loan_custom_payload(number_of_elements) + { Ok(sample) => { let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); (*sample_struct_ptr).init( @@ -396,7 +508,12 @@ pub unsafe extern "C" fn iox2_publisher_loan( } Err(error) => error.into_c_int(), }, - iox2_service_type_e::LOCAL => match publisher.value.as_ref().local.loan_custom_payload(1) { + iox2_service_type_e::LOCAL => match publisher + .value + .as_ref() + .local + .loan_custom_payload(number_of_elements) + { Ok(sample) => { let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); (*sample_struct_ptr).init( diff --git a/iceoryx2-ffi/ffi/src/api/sample.rs b/iceoryx2-ffi/ffi/src/api/sample.rs index b45757f48..e2ba8ff84 100644 --- a/iceoryx2-ffi/ffi/src/api/sample.rs +++ b/iceoryx2-ffi/ffi/src/api/sample.rs @@ -214,26 +214,31 @@ pub unsafe extern "C" fn iox2_sample_user_header( /// /// * `handle` obtained by [`iox2_subscriber_receive()`](crate::iox2_subscriber_receive()) /// * `payload_ptr` a valid, non-null pointer pointing to a [`*const c_void`] pointer. -/// * `payload_len` (optional) either a null poitner or a valid pointer pointing to a [`c_size_t`]. +/// * `number_of_elements` (optional) either a null poitner or a valid pointer pointing to a [`c_size_t`] with +/// the number of elements of the underlying type #[no_mangle] pub unsafe extern "C" fn iox2_sample_payload( handle: iox2_sample_h_ref, payload_ptr: *mut *const c_void, - payload_len: *mut c_size_t, + number_of_elements: *mut c_size_t, ) { handle.assert_non_null(); debug_assert!(!payload_ptr.is_null()); let sample = &mut *handle.as_type(); + let payload = sample.value.as_mut().local.payload(); - let payload = match sample.service_type { - iox2_service_type_e::IPC => sample.value.as_mut().ipc.payload(), - iox2_service_type_e::LOCAL => sample.value.as_mut().local.payload(), + match sample.service_type { + iox2_service_type_e::IPC => { + *payload_ptr = payload.as_ptr().cast(); + } + iox2_service_type_e::LOCAL => { + *payload_ptr = payload.as_ptr().cast(); + } }; - *payload_ptr = payload.as_ptr().cast(); - if !payload_len.is_null() { - *payload_len = payload.len(); + if !number_of_elements.is_null() { + *number_of_elements = sample.value.as_mut().local.header().number_of_elements() as c_size_t; } } diff --git a/iceoryx2-ffi/ffi/src/api/sample_mut.rs b/iceoryx2-ffi/ffi/src/api/sample_mut.rs index ef9f8987a..ee623f913 100644 --- a/iceoryx2-ffi/ffi/src/api/sample_mut.rs +++ b/iceoryx2-ffi/ffi/src/api/sample_mut.rs @@ -157,7 +157,7 @@ pub unsafe extern "C" fn iox2_sample_mut_move( /// /// # Safety /// -/// * `handle` obtained by [`iox2_publisher_loan()`](crate::iox2_publisher_loan()) +/// * `handle` obtained by [`iox2_publisher_loan_slice_uninit()`](crate::iox2_publisher_loan_slice_uninit()) /// * `header_ptr` a valid, non-null pointer pointing to a [`*const c_void`] pointer. #[no_mangle] pub unsafe extern "C" fn iox2_sample_mut_user_header( @@ -181,7 +181,7 @@ pub unsafe extern "C" fn iox2_sample_mut_user_header( /// /// # Safety /// -/// * `handle` obtained by [`iox2_publisher_loan()`](crate::iox2_publisher_loan()) +/// * `handle` obtained by [`iox2_publisher_loan_slice_uninit()`](crate::iox2_publisher_loan_slice_uninit()) /// * `header_struct_ptr` - Must be either a NULL pointer or a pointer to a valid /// [`iox2_publish_subscribe_header_t`]. If it is a NULL pointer, the storage will be allocated on the heap. /// * `header_handle_ptr` valid pointer to a [`iox2_publish_subscribe_header_h`]. @@ -218,7 +218,7 @@ pub unsafe extern "C" fn iox2_sample_mut_header( /// /// # Safety /// -/// * `handle` obtained by [`iox2_publisher_loan()`](crate::iox2_publisher_loan()) +/// * `handle` obtained by [`iox2_publisher_loan_slice_uninit()`](crate::iox2_publisher_loan_slice_uninit()) /// * `header_ptr` a valid, non-null pointer pointing to a [`*const c_void`] pointer. #[no_mangle] pub unsafe extern "C" fn iox2_sample_mut_user_header_mut( @@ -242,28 +242,32 @@ pub unsafe extern "C" fn iox2_sample_mut_user_header_mut( /// /// # Safety /// -/// * `handle` obtained by [`iox2_publisher_loan()`](crate::iox2_publisher_loan()) +/// * `handle` obtained by [`iox2_publisher_loan_slice_uninit()`](crate::iox2_publisher_loan_slice_uninit()) /// * `payload_ptr` a valid, non-null pointer pointing to a [`*const c_void`] pointer. /// * `payload_len` (optional) either a null poitner or a valid pointer pointing to a [`c_size_t`]. #[no_mangle] pub unsafe extern "C" fn iox2_sample_mut_payload_mut( handle: iox2_sample_mut_h_ref, payload_ptr: *mut *mut c_void, - payload_len: *mut c_size_t, + number_of_elements: *mut c_size_t, ) { handle.assert_non_null(); debug_assert!(!payload_ptr.is_null()); let sample = &mut *handle.as_type(); + let payload = sample.value.as_mut().ipc.payload_mut(); - let payload = match sample.service_type { - iox2_service_type_e::IPC => sample.value.as_mut().ipc.payload_mut(), - iox2_service_type_e::LOCAL => sample.value.as_mut().local.payload_mut(), + match sample.service_type { + iox2_service_type_e::IPC => { + *payload_ptr = payload.as_mut_ptr().cast(); + } + iox2_service_type_e::LOCAL => { + *payload_ptr = payload.as_mut_ptr().cast(); + } }; - *payload_ptr = payload.as_mut_ptr().cast(); - if !payload_len.is_null() { - *payload_len = payload.len(); + if !number_of_elements.is_null() { + *number_of_elements = sample.value.as_mut().local.header().number_of_elements() as c_size_t; } } @@ -271,28 +275,32 @@ pub unsafe extern "C" fn iox2_sample_mut_payload_mut( /// /// # Safety /// -/// * `handle` obtained by [`iox2_publisher_loan()`](crate::iox2_publisher_loan()) +/// * `handle` obtained by [`iox2_publisher_loan_slice_uninit()`](crate::iox2_publisher_loan_slice_uninit()) /// * `payload_ptr` a valid, non-null pointer pointing to a [`*const c_void`] pointer. /// * `payload_len` (optional) either a null poitner or a valid pointer pointing to a [`c_size_t`]. #[no_mangle] pub unsafe extern "C" fn iox2_sample_mut_payload( handle: iox2_sample_mut_h_ref, payload_ptr: *mut *const c_void, - payload_len: *mut c_size_t, + number_of_elements: *mut c_size_t, ) { handle.assert_non_null(); debug_assert!(!payload_ptr.is_null()); let sample = &mut *handle.as_type(); + let payload = sample.value.as_mut().ipc.payload_mut(); - let payload = match sample.service_type { - iox2_service_type_e::IPC => sample.value.as_mut().ipc.payload(), - iox2_service_type_e::LOCAL => sample.value.as_mut().local.payload(), + match sample.service_type { + iox2_service_type_e::IPC => { + *payload_ptr = payload.as_mut_ptr().cast(); + } + iox2_service_type_e::LOCAL => { + *payload_ptr = payload.as_mut_ptr().cast(); + } }; - *payload_ptr = payload.as_ptr().cast(); - if !payload_len.is_null() { - *payload_len = payload.len(); + if !number_of_elements.is_null() { + *number_of_elements = sample.value.as_mut().local.header().number_of_elements() as c_size_t; } } @@ -300,7 +308,7 @@ pub unsafe extern "C" fn iox2_sample_mut_payload( /// /// # Safety /// -/// * `handle` obtained by [`iox2_publisher_loan()`](crate::iox2_publisher_loan()) +/// * `handle` obtained by [`iox2_publisher_loan_slice_uninit()`](crate::iox2_publisher_loan_slice_uninit()) /// * `number_of_recipients`, can be null or must point to a valid [`c_size_t`] to store the number /// of subscribers that received the sample #[no_mangle] diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs index 0252cec04..b87464509 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs @@ -480,6 +480,52 @@ pub unsafe extern "C" fn iox2_service_builder_pub_sub_set_max_subscribers( } } +/// Sets the payload alignment for the builder +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_pub_sub_h_ref`] +/// obtained by [`iox2_service_builder_pub_sub`](crate::iox2_service_builder_pub_sub). +/// * `value` - The value to set the payload alignment to +/// +/// # Safety +/// +/// * `service_builder_handle` must be valid handles +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_pub_sub_set_payload_alignment( + service_builder_handle: iox2_service_builder_pub_sub_h_ref, + value: c_size_t, +) { + service_builder_handle.assert_non_null(); + + let service_builder_struct = unsafe { &mut *service_builder_handle.as_type() }; + + match service_builder_struct.service_type { + iox2_service_type_e::IPC => { + let service_builder = + ManuallyDrop::take(&mut service_builder_struct.value.as_mut().ipc); + + let service_builder = ManuallyDrop::into_inner(service_builder.pub_sub); + service_builder_struct.set(ServiceBuilderUnion::new_ipc_pub_sub( + service_builder.payload_alignment( + Alignment::new(value).unwrap_or(Alignment::new_unchecked(8)), + ), + )); + } + iox2_service_type_e::LOCAL => { + let service_builder = + ManuallyDrop::take(&mut service_builder_struct.value.as_mut().local); + + let service_builder = ManuallyDrop::into_inner(service_builder.pub_sub); + service_builder_struct.set(ServiceBuilderUnion::new_local_pub_sub( + service_builder.payload_alignment( + Alignment::new(value).unwrap_or(Alignment::new_unchecked(8)), + ), + )); + } + } +} + /// Sets the history size /// /// # Arguments diff --git a/iceoryx2/src/port/publisher.rs b/iceoryx2/src/port/publisher.rs index ce4b9fb37..e7e4b7b30 100644 --- a/iceoryx2/src/port/publisher.rs +++ b/iceoryx2/src/port/publisher.rs @@ -704,6 +704,11 @@ impl self.data_segment.config.unable_to_deliver_strategy } + /// Returns the maximum slice length configured for this [`Publisher`]. + pub fn max_slice_len(&self) -> usize { + self.data_segment.config.max_slice_len + } + fn allocate(&self, layout: Layout) -> Result { let msg = "Unable to allocate Sample with";